Repository: lexxmark/QtnProperty Branch: master Commit: 18cde1486a0f Files: 251 Total size: 1.2 MB Directory structure: gitextract_oykrz322/ ├── .clang-format ├── .gitignore ├── .travis.yml ├── AUTHORS ├── CHANGELOG ├── Demo/ │ ├── AB/ │ │ ├── PropertyABColor.cpp │ │ ├── PropertyABColor.h │ │ ├── PropertyDelegateABColor.cpp │ │ └── PropertyDelegateABColor.h │ ├── Demo.pef │ ├── Demo.peg.cpp │ ├── Demo.peg.h │ ├── Demo.pro │ ├── Freq/ │ │ ├── PropertyDelegateFreq.cpp │ │ ├── PropertyDelegateFreq.h │ │ ├── PropertyFreq.cpp │ │ └── PropertyFreq.h │ ├── Int/ │ │ ├── PropertyDelegateIntList.cpp │ │ └── PropertyDelegateIntList.h │ ├── Layer/ │ │ ├── PropertyDelegateLayer.cpp │ │ ├── PropertyDelegateLayer.h │ │ ├── PropertyLayer.cpp │ │ └── PropertyLayer.h │ ├── MainWindow.cpp │ ├── MainWindow.h │ ├── MainWindow.ui │ ├── PenWidth/ │ │ ├── PropertyDelegatePenWidth.cpp │ │ ├── PropertyDelegatePenWidth.h │ │ ├── PropertyPenWidth.cpp │ │ └── PropertyPenWidth.h │ ├── main.cpp │ ├── mydialog.cpp │ ├── mydialog.h │ └── mydialog.ui ├── Docs/ │ ├── Doxyfile │ └── Example/ │ ├── TextAttributes.pef │ ├── TextAttributes.peg.cpp │ └── TextAttributes.peg.h ├── Internal/ │ ├── BaseConfig.pri │ └── TargetConfig.pri ├── LICENSE ├── NOTICE ├── PEG/ │ ├── Bison.pri │ ├── Flex.pri │ ├── PEG.pri │ ├── PEG.pro │ ├── PropertyEnum.l │ ├── PropertyEnum.y │ ├── PropertyEnumGenerator.cpp │ ├── PropertyEnumGenerator.h │ ├── PropertyEnumGeneratorCommon.h │ └── main.cpp ├── QtnProperty/ │ ├── Auxiliary/ │ │ ├── PropertyAux.h │ │ ├── PropertyDelegateInfo.cpp │ │ ├── PropertyDelegateInfo.h │ │ ├── PropertyMacro.h │ │ └── PropertyTemplates.h │ ├── Config.h │ ├── Core/ │ │ ├── PropertyBool.cpp │ │ ├── PropertyBool.h │ │ ├── PropertyDouble.cpp │ │ ├── PropertyDouble.h │ │ ├── PropertyEnum.cpp │ │ ├── PropertyEnum.h │ │ ├── PropertyEnumFlags.cpp │ │ ├── PropertyEnumFlags.h │ │ ├── PropertyFloat.cpp │ │ ├── PropertyFloat.h │ │ ├── PropertyInt.cpp │ │ ├── PropertyInt.h │ │ ├── PropertyQPoint.cpp │ │ ├── PropertyQPoint.h │ │ ├── PropertyQPointF.cpp │ │ ├── PropertyQPointF.h │ │ ├── PropertyQRect.cpp │ │ ├── PropertyQRect.h │ │ ├── PropertyQRectF.cpp │ │ ├── PropertyQRectF.h │ │ ├── PropertyQSize.cpp │ │ ├── PropertyQSize.h │ │ ├── PropertyQSizeF.cpp │ │ ├── PropertyQSizeF.h │ │ ├── PropertyQString.cpp │ │ ├── PropertyQString.h │ │ ├── PropertyUInt.cpp │ │ └── PropertyUInt.h │ ├── CustomPropertyEditorDialog.cpp │ ├── CustomPropertyEditorDialog.h │ ├── CustomPropertyEditorDialog.ui │ ├── CustomPropertyOptionsDialog.cpp │ ├── CustomPropertyOptionsDialog.h │ ├── CustomPropertyOptionsDialog.ui │ ├── CustomPropertyWidget.cpp │ ├── CustomPropertyWidget.h │ ├── Delegates/ │ │ ├── Core/ │ │ │ ├── PropertyDelegateBool.cpp │ │ │ ├── PropertyDelegateBool.h │ │ │ ├── PropertyDelegateDouble.cpp │ │ │ ├── PropertyDelegateDouble.h │ │ │ ├── PropertyDelegateEnum.cpp │ │ │ ├── PropertyDelegateEnum.h │ │ │ ├── PropertyDelegateEnumFlags.cpp │ │ │ ├── PropertyDelegateEnumFlags.h │ │ │ ├── PropertyDelegateFloat.cpp │ │ │ ├── PropertyDelegateFloat.h │ │ │ ├── PropertyDelegateInt.cpp │ │ │ ├── PropertyDelegateInt.h │ │ │ ├── PropertyDelegateQPoint.cpp │ │ │ ├── PropertyDelegateQPoint.h │ │ │ ├── PropertyDelegateQPointF.cpp │ │ │ ├── PropertyDelegateQPointF.h │ │ │ ├── PropertyDelegateQRect.cpp │ │ │ ├── PropertyDelegateQRect.h │ │ │ ├── PropertyDelegateQRectF.cpp │ │ │ ├── PropertyDelegateQRectF.h │ │ │ ├── PropertyDelegateQSize.cpp │ │ │ ├── PropertyDelegateQSize.h │ │ │ ├── PropertyDelegateQSizeF.cpp │ │ │ ├── PropertyDelegateQSizeF.h │ │ │ ├── PropertyDelegateQString.cpp │ │ │ ├── PropertyDelegateQString.h │ │ │ ├── PropertyDelegateUInt.cpp │ │ │ └── PropertyDelegateUInt.h │ │ ├── GUI/ │ │ │ ├── PropertyDelegateButton.cpp │ │ │ ├── PropertyDelegateButton.h │ │ │ ├── PropertyDelegateQBrush.cpp │ │ │ ├── PropertyDelegateQBrush.h │ │ │ ├── PropertyDelegateQColor.cpp │ │ │ ├── PropertyDelegateQColor.h │ │ │ ├── PropertyDelegateQFont.cpp │ │ │ ├── PropertyDelegateQFont.h │ │ │ ├── PropertyDelegateQPen.cpp │ │ │ ├── PropertyDelegateQPen.h │ │ │ ├── PropertyDelegateQVector3D.cpp │ │ │ └── PropertyDelegateQVector3D.h │ │ ├── PropertyDelegate.cpp │ │ ├── PropertyDelegate.h │ │ ├── PropertyDelegateAux.cpp │ │ ├── PropertyDelegateAux.h │ │ ├── PropertyDelegateFactory.cpp │ │ ├── PropertyDelegateFactory.h │ │ └── Utils/ │ │ ├── PropertyDelegateGeoCoord.cpp │ │ ├── PropertyDelegateGeoCoord.h │ │ ├── PropertyDelegateGeoPoint.cpp │ │ ├── PropertyDelegateGeoPoint.h │ │ ├── PropertyDelegateMisc.cpp │ │ ├── PropertyDelegateMisc.h │ │ ├── PropertyDelegatePropertySet.cpp │ │ ├── PropertyDelegatePropertySet.h │ │ ├── PropertyDelegateSliderBox.cpp │ │ ├── PropertyDelegateSliderBox.h │ │ ├── PropertyEditorAux.cpp │ │ ├── PropertyEditorAux.h │ │ ├── PropertyEditorHandler.cpp │ │ └── PropertyEditorHandler.h │ ├── Enum.cpp │ ├── Enum.h │ ├── FunctionalHelpers.h │ ├── GUI/ │ │ ├── PropertyButton.cpp │ │ ├── PropertyButton.h │ │ ├── PropertyQBrush.cpp │ │ ├── PropertyQBrush.h │ │ ├── PropertyQColor.cpp │ │ ├── PropertyQColor.h │ │ ├── PropertyQFont.cpp │ │ ├── PropertyQFont.h │ │ ├── PropertyQPen.cpp │ │ ├── PropertyQPen.h │ │ ├── PropertyQVector3D.cpp │ │ └── PropertyQVector3D.h │ ├── IQtnPropertyStateProvider.h │ ├── Install.cpp │ ├── Install.h │ ├── MultiProperty.cpp │ ├── MultiProperty.h │ ├── Property.cpp │ ├── Property.h │ ├── PropertyBase.cpp │ ├── PropertyBase.h │ ├── PropertyConnector.cpp │ ├── PropertyConnector.h │ ├── PropertyCore.h │ ├── PropertyDelegateAttrs.h │ ├── PropertyDelegateMetaEnum.cpp │ ├── PropertyDelegateMetaEnum.h │ ├── PropertyGUI.h │ ├── PropertyInt64.cpp │ ├── PropertyInt64.h │ ├── PropertyQKeySequence.cpp │ ├── PropertyQKeySequence.h │ ├── PropertyQVariant.cpp │ ├── PropertyQVariant.h │ ├── PropertySet.cpp │ ├── PropertySet.h │ ├── PropertyUInt64.cpp │ ├── PropertyUInt64.h │ ├── PropertyView.cpp │ ├── PropertyView.h │ ├── PropertyWidget.cpp │ ├── PropertyWidget.h │ ├── PropertyWidgetEx.cpp │ ├── PropertyWidgetEx.h │ ├── QObjectPropertySet.cpp │ ├── QObjectPropertySet.h │ ├── QObjectPropertyWidget.cpp │ ├── QObjectPropertyWidget.h │ ├── QtnProperty.pri │ ├── QtnProperty.pro │ ├── QtnProperty.qrc │ ├── StructPropertyBase.h │ ├── Translations/ │ │ ├── en.ts │ │ └── ru.ts │ ├── Utils/ │ │ ├── AccessibilityProxy.cpp │ │ ├── AccessibilityProxy.h │ │ ├── DoubleSpinBox.cpp │ │ ├── DoubleSpinBox.h │ │ ├── InplaceEditing.cpp │ │ ├── InplaceEditing.h │ │ ├── MultilineTextDialog.cpp │ │ ├── MultilineTextDialog.h │ │ ├── MultilineTextDialog.ui │ │ ├── QtnCompleterItemDelegate.cpp │ │ ├── QtnCompleterItemDelegate.h │ │ ├── QtnCompleterLineEdit.cpp │ │ ├── QtnCompleterLineEdit.h │ │ ├── QtnConnections.cpp │ │ ├── QtnConnections.h │ │ ├── QtnInt64SpinBox.cpp │ │ └── QtnInt64SpinBox.h │ ├── VarProperty.cpp │ └── VarProperty.h ├── QtnProperty.pro ├── QtnPropertyDepend.pri ├── README.md ├── TODO └── Tests/ ├── PEG/ │ ├── test.pef │ ├── test.peg.cpp │ ├── test.peg.h │ ├── test2.pef │ ├── test2.peg.cpp │ └── test2.peg.h ├── TestEnum.cpp ├── TestEnum.h ├── TestGeneratedProperty.cpp ├── TestGeneratedProperty.h ├── TestProperty.cpp ├── TestProperty.h ├── Tests.pro ├── main.cpp └── suite_squish_test_suit/ ├── envvars ├── suite.conf └── tst_gui_test/ └── test.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .clang-format ================================================ --- IndentWidth: 4 TabWidth: 4 ColumnLimit: 80 --- Language: Cpp AccessModifierOffset: -4 AlignAfterOpenBracket: false AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlines: DontAlign AlignOperands: false AlignTrailingComments: false AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: true BinPackArguments: true BinPackParameters: true BraceWrapping: AfterStruct: true AfterClass: true AfterControlStatement: true AfterEnum: true AfterFunction: true AfterNamespace: true AfterUnion: true BeforeCatch: false BeforeElse: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom BreakBeforeInheritanceComma: true BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeComma BreakStringLiterals: true CompactNamespaces: false ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: false DerivePointerAlignment: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true ForEachMacros: ['foreach'] IncludeIsMainRegex: '' IndentCaseLabels: true IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: false NamespaceIndentation: None PointerAlignment: Right ReflowComments: false SortIncludes: false SortUsingDeclarations: false SpaceAfterCStyleCast: true SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false SpacesInAngles: false SpacesInCStyleCastParentheses: false SpacesInContainerLiterals: true SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp11 UseTab: Always ================================================ FILE: .gitignore ================================================ /tmp/ /bin*/ build*/ /workdir/ *.pro.user *.lexer.* *.parser.* *~ *.directory *.autosave *Thumbs.db *.qm *.orig ================================================ FILE: .travis.yml ================================================ language: cpp dist: trusty compiler: - gcc branches: only: - master - develop os: - linux before_install: - sudo add-apt-repository ppa:beineri/opt-qt593-trusty -y - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y - sudo apt-get update -q install: - sudo apt-get install flex bison - sudo apt-get install qt59base qt59script qt59tools - source /opt/qt59/bin/qt59-env.sh - sudo apt-get install -qq g++-4.8 - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90 script: - qmake - make - ./bin-linux-gcc-x86_64/QtnPropertyTests ================================================ FILE: AUTHORS ================================================ Original author: Alexey Zhondin Modifications/Extensions by: Alexandra Cherdantseva ================================================ FILE: CHANGELOG ================================================ QtnProperty =========== v2.0.3 23.12.2020 [FIX] Register QVariant property delegate v2.0.2 18.12.2020 [FIX] Don't break property view splitter with drag action v2.0.1 30.11.2020 [REFINE] Show splitter line and change mouse cursor only for splittable property delegates [FIX] Correct stripping redundant digits after decimal point when converting floating-point value to locale string [FIX] Fixed compilation with Qt 5.15 v2.0.0 20.11.2020 [NEW] Multi-property set with QtnMultiProperty (Used in QObjectPropertyWidget if multiple objects selected) [NEW] Delegate attributes for floating-point properties: multiplier, precision [NEW] Delegate attributes for numeric properties: min, max, step, suffix [NEW] Delegate attributes for string properties: placeholder, multiline_edit [NEW] Apply delegate attributes for sub-properties (see QPoint, QSize etc.) [NEW] QtnDoubleSpinBox - trailing zeros removed (used in floating-point properties) [NEW] QtnInt64SpinBox - used in uint and int64 properties [NEW] QtnCompleterLineEdit - autocomplete popup view with input text highlighted (used in QtnPropertyDelegateQStringCallback) [NEW] Property delegates for: int64, uint64, QPointF, QSizeF, QRectF, QVector3D, Button, QBrush, QPen, QVariant, QKeySequence [NEW] Editing QVariant with CustomProperyEditorDialog and CustomPropertyWidget [NEW] Ability to set custom property delegate factory for QtnPropertyView with delegateFactory()->setSuperFactory(factory) [NEW] QtnPropertyDelegateMetaEnum - property delegate for registered enums (Register with QtnPropertyDelegateMetaEnum::Register, and use custom delegate factory) [NEW] QtnPropertyStateResettable and Reset button [NEW] QtnPropertyStateUnlockable and Lock/Unlock button [NEW] Update delegate with QtnPropertyChangeReasonUpdateDelegate [NEW] Support dark theme on MacOS [FIX] QColor property delegate with circle shape draws valid color [FIX] Update property view when changing QObject property values outside property editor [FIX] SliderBox delegate works with huge value range ================================================ FILE: Demo/AB/PropertyABColor.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyABColor.h" void QtnPropertyABColor::invokeClick() { emit click(this); } void QtnPropertyABColor::setClickHandler( const std::function &clickHandler) { QObject::connect(this, &QtnPropertyABColor::click, clickHandler); } bool QtnPropertyMyColor::fromActualValue(ValueType actualValue, BaseValueTypeStore& baseValue) const { baseValue = QColor::fromRgb(actualValue.red, actualValue.green, actualValue.blue); return true; } bool QtnPropertyMyColor::toActualValue(ValueTypeStore& actualValue, BaseValueType baseValue) const { actualValue.red = baseValue.red(); actualValue.green = baseValue.green(); actualValue.blue = baseValue.blue(); return true; } ================================================ FILE: Demo/AB/PropertyABColor.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_AB_COLOR_H #define PROPERTY_AB_COLOR_H #include "QtnProperty/GUI/PropertyQColor.h" class QtnPropertyABColor : public QtnPropertyQColor { Q_OBJECT QtnPropertyABColor(const QtnPropertyABColor &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyABColor(QObject *parent) : QtnPropertyQColor(parent) { } P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyABColor, QtnPropertyQColor) void invokeClick(); void setClickHandler( const std::function &clickHandler); Q_SIGNALS: void click(const QtnPropertyABColor *property); }; struct MyColor { int red = 0; int green = 0; int blue = 0; }; using QtnPropertyMyColorBase = QtnSinglePropertyBaseAs; class QtnPropertyMyColor : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyMyColor(const QtnPropertyMyColor &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyMyColor(QObject *parent = nullptr) : QtnSinglePropertyValue(parent) { } protected: bool fromActualValue(ValueType actualValue, BaseValueTypeStore& baseValue) const override; bool toActualValue(ValueTypeStore& actualValue, BaseValueType baseValue) const override; P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyMyColor, QtnPropertyMyColorBase) }; #endif // PROPERTY_AB_COLOR_H ================================================ FILE: Demo/AB/PropertyDelegateABColor.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateABColor.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "PropertyABColor.h" void regABColorDelegates() { QtnPropertyDelegateFactory::staticInstance().registerDelegateDefault( &QtnPropertyABColor::staticMetaObject, &qtnCreateDelegate, "LineEditBttn"); } QtnPropertyDelegateABColor::QtnPropertyDelegateABColor( QtnPropertyABColor &owner) : QtnPropertyDelegateQColor(owner) , m_owner(owner) { } QWidget *QtnPropertyDelegateABColor::createValueEditorImpl(QWidget * /*parent*/, const QRect & /*rect*/, QtnInplaceInfo * /*inplaceInfo*/) { m_owner.invokeClick(); return nullptr; } ================================================ FILE: Demo/AB/PropertyDelegateABColor.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_AB_COLOR_H #define PROPERTY_DELEGATE_AB_COLOR_H #include "QtnProperty/Delegates/GUI/PropertyDelegateQColor.h" class QtnPropertyABColor; class QtnPropertyDelegateABColor : public QtnPropertyDelegateQColor { Q_DISABLE_COPY(QtnPropertyDelegateABColor) public: QtnPropertyDelegateABColor(QtnPropertyABColor &owner); protected: QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; private: QtnPropertyABColor &m_owner; }; #endif // PROPERTY_DELEGATE_AB_COLOR_H ================================================ FILE: Demo/Demo.pef ================================================ #include "QtnProperty/PropertyCore.h" #include "QtnProperty/PropertyGUI.h" #include "QtnProperty/PropertyInt64.h" #include "QtnProperty/PropertyUInt64.h" #include "AB/PropertyABColor.h" #include "Layer/PropertyLayer.h" #include "PenWidth/PropertyPenWidth.h" #include "Freq/PropertyFreq.h" #include_cpp #include_cpp enum COLOR { red (1, "red"), blue (2, "blue"), green (3, "green") } enum FLAGS { opt1(1, "Option1"), opt2(2, "Option2"), opt3(4, "Option3") } property_set SamplePS { MyColor myColor { description = "Property to hold MyColor values."; } Bool BoolProperty { description = "Property to hold boolean values."; value = false; } Button ButtonProperty { description = "Start calculate a long operation."; clickHandler = [](const QtnPropertyButton* bttn) { qDebug() << Q_FUNC_INFO << "Button has clicked: " << bttn; }; delegate { title = "Click me"; } } Button ButtonLinkProperty { clickHandler = [](const QtnPropertyButton* bttn) { qDebug() << Q_FUNC_INFO << "Link has clicked: " << bttn; }; delegate Link { title = "Click on me"; } } ABColor RGBColor { description = "ABColor property with RGB components"; value = QColor(123, 150, 10); clickHandler = [this](const QtnPropertyABColor* color) { qDebug() << Q_FUNC_INFO << "Color has clicked: " << color; RGBColor = QColor::fromRgb(qrand()%255, qrand()%255, qrand()%255); }; delegate { rgbSubItems = true; } } QColor ColorSolidDelegate { description = "QColor property with Solid delegate"; value = QColor(13, 150, 10); delegate Solid; } Float FloatPropertySliderBox { displayName = "Float Property Slider Box"; description = "Property to hold float values in range [0, 10]."; value = 1.f; minValue = 0; maxValue = 10.f; stepValue = 0.1f; delegate SliderBox { fillColor = QColor::fromRgb(170, 170, 255); drawBorder = false; } } Float FloatPercent { description = "Property to hold float values in range [0-1] visible as [0%-100%]."; value = 0.5f; minValue = 0.f; maxValue = 1.f; delegate { multiplier = 100.0; suffix = "%"; } } Double DoublePercent { description = "Property to hold double values in range [0-1] visible as [0%-100%]."; value = 0.5; minValue = 0.0; maxValue = 1.0; delegate { multiplier = 100.0; precision = 10; suffix = "%"; } } Float FloatIntRangeSliderBox { description = "Property to hold float values in full range."; value = 111.f; minValue = -float(1 << std::numeric_limits::digits); maxValue = float(1 << std::numeric_limits::digits); delegate SliderBox { fillColor = QColor::fromRgb(170, 170, 255); drawBorder = false; } } Double DoubleFullRangeSliderBox { description = "Property to hold double values in full range."; value = 1111.0; minValue = -double(1LL << std::numeric_limits::digits); maxValue = double(1LL << std::numeric_limits::digits); delegate SliderBox { fillColor = QColor::fromRgb(170, 170, 255); drawBorder = false; } } Double DoubleProperty { description = "Property to hold double values in range [10, 20]."; value = 12.3; minValue = 10; maxValue = 20; stepValue = 0.5; } Float FloatProperty { description = "Property to hold float values in range [-10, 0]."; value = -3.5; minValue = -10; maxValue = 0; stepValue = 0.5; } Int IntProperty { description = "Property to hold integer values with changing step 15."; value = 10; stepValue = 15; } Int IntPropertyComboBox { description = "Property to hold integer values with changing step 15."; value = 10; stepValue = 15; delegate IntList { values = QVariant::fromValue(QList() << 10 << 12 << 15); } } UInt UIntProperty { description = "Property to hold unsigned integer values in range [100, 200]."; value = 100; minValue = 100; maxValue = 200; } Int64 Int64Property { description = "Property to hold signed integer 64-bit value"; value = -(1LL << 35); delegate { step = 100000; } } UInt64 UInt64Property { description = "Property to hold signed integer 64-bit value"; value = 1ULL << 63; } Int64 Int64SliderBox { description = "Property to hold signed integer 64-bit value with slider box"; value = -(1LL << 34); delegate SliderBox { } } UInt64 UInt64SliderBox { description = "Property to hold unsigned integer 64-bit value with slider box"; value = 1ULL << 58; delegate SliderBox { } } Enum EnumProperty { description = "Property to hold enum value (color)."; enumInfo = &COLOR::info(); value = COLOR::red; } EnumFlags EnumFlagsProperty { description = "Property to hold combination of enum values (options)."; enumInfo = &FLAGS::info(); value = FLAGS::opt2; } QString QStringValue { description = "Property to hold QString value."; value = "Hello world!"; } Bool EnableSubPropertySet { description = "Enable/Disable Sub-PropertySet."; value = false; slot propertyDidChange { SubPropertySet.switchState(QtnPropertyStateImmutable, !EnableSubPropertySet); } } property_set SubPropertySetType SubPropertySet { description = "This property set is part of the root property set."; state = QtnPropertyStateImmutable; Bool SwitchProperty { description = "Boolean property with customized True/False values."; value = true; delegate ComboBox { labelTrue = "On"; labelFalse = "Off"; } } QStringCallback ReadOnlyString { description = "This property is callback and read-only."; state = QtnPropertyStateImmutable; callbackValueGet = [this] ()->QString { if (SwitchProperty) return "Switch is on"; else return "Switch is off"; }; } QString FileNameProperty { description = "QString property tuned to handle file names."; value = "~/test_file.txt"; delegate File { invalidColor = QColor(Qt::red); acceptMode = QFileDialog::AcceptSave; nameFilters = QStringList() << "Text files (*.txt)" << "All files (*)"; } } QString FolderNameProperty { description = "QString property tuned to handle folder names."; value = "/var"; delegate File { invalidColor = QColor(Qt::blue); fileMode = QFileDialog::DirectoryOnly; } } QString StringFromList { description = "QString property with list of acepted values (one, two, three, four)."; value = "two"; delegate ComboBox { items = QStringList() << "one" << "two" << "three" << "four"; } } QColor CircleShapeColor { description = "QColor property with delegate tuned to draw circle"; value = QColor(255, 100, 100); delegate { shape = QtnColorDelegateShapeCircle; } } } QPoint QPointProperty { description = "Property to hold QPoint value."; value = QPoint(-10, 10); } QSize QSizeProperty { description = "Property to hold QSize value."; value = QSize(100, 200); } QRect QRectProperty { description = "Property to hold QRect value."; value = QRect(10, 10, 200, 200); } QPointF QPointFProperty { description = "Property to hold QPointF value."; value = QPointF(-10.5, 10.2); } QSizeF QSizeFProperty { description = "Property to hold QSizeF value."; value = QSizeF(100.0, 200.1); } QRectF QRectFProperty { description = "Property to hold QRectF value."; value = QRectF(10.23, 10.4, 200.2, 200.6); } QVector3D QVector3DProperty { description = "Property to hold QVector3D value."; value = QVector3D(5, 6, 7); delegate { multiplier = 100.0 / 255.0; min = 0; max = 255; precision = 5; suffix = "%"; z = QVariantMap({ { QString("name"), QString("SliderBox")}, { QString("precision"), 3 }, }); } } QColor QColorProperty { description = "Property to hold QColor value."; value = Qt::blue; slot propertyDidChange { qDebug() << Q_FUNC_INFO << "Property has changed: " << &QColorProperty; } } QFont QFontProperty { description = "Property to hold QFont value."; value = QFont("Sans Serif", 14); } Freq FreqProperty { description = "Property to hold frequency values."; value = 15; unit = FreqUnit::KHz; } Layer LayerProperty { description = "Property to hold layer."; value = 0; } QBrushStyle BrushStyleProperty { description = "Property to hold QBrushStyle enum."; value = Qt::HorPattern; } PenWidth PenWidthProperty { description = "Property to hold PenWidth enum."; value = PenWidth::Middle; } QPenStyle PenStyleProperty { description = "Property to hold pen style values."; value = Qt::DashLine; } QPen PenProperty { description = "Property to hold QPen values."; delegate { editColor = true; editStyle = true; editWidth = true; } } QString QStringCallbackProperty { description = "Property to hold QString values with candidates."; } extern property_set SubPropertySetType SubPropertySet2 { state = QtnPropertyStateCollapsed; } } ================================================ FILE: Demo/Demo.peg.cpp ================================================ #include "Demo.peg.h" #include #include static QtnEnumInfo& create_COLOR_info() { QVector staticValues; 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; } static QtnEnumInfo& create_FLAGS_info() { QVector staticValues; staticValues.append(QtnEnumValueInfo(FLAGS::opt1, "opt1", "Option1")); staticValues.append(QtnEnumValueInfo(FLAGS::opt2, "opt2", "Option2")); staticValues.append(QtnEnumValueInfo(FLAGS::opt3, "opt3", "Option3")); static QtnEnumInfo enumInfo("FLAGS", staticValues); return enumInfo; } const QtnEnumInfo& FLAGS::info() { static QtnEnumInfo& enumInfo = create_FLAGS_info(); return enumInfo; } QtnPropertySetSubPropertySetType::QtnPropertySetSubPropertySetType(QObject* parent) : QtnPropertySet(parent) , SwitchProperty(*qtnCreateProperty(this)) , ReadOnlyString(*qtnCreateProperty(this)) , FileNameProperty(*qtnCreateProperty(this)) , FolderNameProperty(*qtnCreateProperty(this)) , StringFromList(*qtnCreateProperty(this)) , CircleShapeColor(*qtnCreateProperty(this)) { init(); connectSlots(); connectDelegates(); } QtnPropertySetSubPropertySetType::~QtnPropertySetSubPropertySetType() { disconnectSlots(); } QtnPropertySetSubPropertySetType& QtnPropertySetSubPropertySetType::operator=(const QtnPropertySetSubPropertySetType& other) { Q_UNUSED(other); SwitchProperty = other.SwitchProperty; ReadOnlyString = other.ReadOnlyString; FileNameProperty = other.FileNameProperty; FolderNameProperty = other.FolderNameProperty; StringFromList = other.StringFromList; CircleShapeColor = other.CircleShapeColor; return *this; } QtnPropertySet* QtnPropertySetSubPropertySetType::createNewImpl(QObject* parentForNew) const { return new QtnPropertySetSubPropertySetType(parentForNew); } QtnPropertySet* QtnPropertySetSubPropertySetType::createCopyImpl(QObject* parentForCopy) const { QtnPropertySetSubPropertySetType* p = new QtnPropertySetSubPropertySetType(parentForCopy); *p = *this; return p; } bool QtnPropertySetSubPropertySetType::copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) { Q_UNUSED(ignoreMask); auto theCopyFrom = qobject_cast(propertySetCopyFrom); if (!theCopyFrom) return false; if (!(theCopyFrom->SwitchProperty.state() & ignoreMask)) { SwitchProperty = theCopyFrom->SwitchProperty; } if (!(theCopyFrom->ReadOnlyString.state() & ignoreMask)) { ReadOnlyString = theCopyFrom->ReadOnlyString; } if (!(theCopyFrom->FileNameProperty.state() & ignoreMask)) { FileNameProperty = theCopyFrom->FileNameProperty; } if (!(theCopyFrom->FolderNameProperty.state() & ignoreMask)) { FolderNameProperty = theCopyFrom->FolderNameProperty; } if (!(theCopyFrom->StringFromList.state() & ignoreMask)) { StringFromList = theCopyFrom->StringFromList; } if (!(theCopyFrom->CircleShapeColor.state() & ignoreMask)) { CircleShapeColor = theCopyFrom->CircleShapeColor; } return true; } void QtnPropertySetSubPropertySetType::init() { static QString SubPropertySet_name = QStringLiteral("SubPropertySet"); setName(SubPropertySet_name); static QString description = "This property set is part of the root property set."; setDescription(description); setState(QtnPropertyStateImmutable); // start children initialization static QString SwitchProperty_name = QStringLiteral("SwitchProperty"); SwitchProperty.setName(SwitchProperty_name); static QString SwitchProperty_description = "Boolean property with customized True/False values."; SwitchProperty.setDescription(SwitchProperty_description); SwitchProperty.setValue(true); static QString ReadOnlyString_name = QStringLiteral("ReadOnlyString"); ReadOnlyString.setName(ReadOnlyString_name); ReadOnlyString.setCallbackValueGet([this] ()->QString { if (SwitchProperty) return "Switch is on"; else return "Switch is off"; }); static QString ReadOnlyString_description = "This property is callback and read-only."; ReadOnlyString.setDescription(ReadOnlyString_description); ReadOnlyString.setState(QtnPropertyStateImmutable); static QString FileNameProperty_name = QStringLiteral("FileNameProperty"); FileNameProperty.setName(FileNameProperty_name); static QString FileNameProperty_description = "QString property tuned to handle file names."; FileNameProperty.setDescription(FileNameProperty_description); FileNameProperty.setValue("~/test_file.txt"); static QString FolderNameProperty_name = QStringLiteral("FolderNameProperty"); FolderNameProperty.setName(FolderNameProperty_name); static QString FolderNameProperty_description = "QString property tuned to handle folder names."; FolderNameProperty.setDescription(FolderNameProperty_description); FolderNameProperty.setValue("/var"); static QString StringFromList_name = QStringLiteral("StringFromList"); StringFromList.setName(StringFromList_name); static QString StringFromList_description = "QString property with list of acepted values (one, two, three, four)."; StringFromList.setDescription(StringFromList_description); StringFromList.setValue("two"); static QString CircleShapeColor_name = QStringLiteral("CircleShapeColor"); CircleShapeColor.setName(CircleShapeColor_name); static QString CircleShapeColor_description = "QColor property with delegate tuned to draw circle"; CircleShapeColor.setDescription(CircleShapeColor_description); CircleShapeColor.setValue(QColor(255, 100, 100)); // end children initialization } void QtnPropertySetSubPropertySetType::connectSlots() { } void QtnPropertySetSubPropertySetType::disconnectSlots() { } void QtnPropertySetSubPropertySetType::connectDelegates() { SwitchProperty.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "ComboBox"; info.attributes["labelFalse"] = "Off"; info.attributes["labelTrue"] = "On"; return info; }); FileNameProperty.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "File"; info.attributes["acceptMode"] = QFileDialog::AcceptSave; info.attributes["invalidColor"] = QColor(Qt::red); info.attributes["nameFilters"] = QStringList() << "Text files (*.txt)" << "All files (*)"; return info; }); FolderNameProperty.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "File"; info.attributes["fileMode"] = QFileDialog::DirectoryOnly; info.attributes["invalidColor"] = QColor(Qt::blue); return info; }); StringFromList.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "ComboBox"; info.attributes["items"] = QStringList() << "one" << "two" << "three" << "four"; return info; }); CircleShapeColor.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.attributes["shape"] = QtnColorDelegateShapeCircle; return info; }); } QtnPropertySetSamplePS::QtnPropertySetSamplePS(QObject* parent) : QtnPropertySet(parent) , myColor(*qtnCreateProperty(this)) , BoolProperty(*qtnCreateProperty(this)) , ButtonProperty(*qtnCreateProperty(this)) , ButtonLinkProperty(*qtnCreateProperty(this)) , RGBColor(*qtnCreateProperty(this)) , ColorSolidDelegate(*qtnCreateProperty(this)) , FloatPropertySliderBox(*qtnCreateProperty(this)) , FloatPercent(*qtnCreateProperty(this)) , DoublePercent(*qtnCreateProperty(this)) , FloatIntRangeSliderBox(*qtnCreateProperty(this)) , DoubleFullRangeSliderBox(*qtnCreateProperty(this)) , DoubleProperty(*qtnCreateProperty(this)) , FloatProperty(*qtnCreateProperty(this)) , IntProperty(*qtnCreateProperty(this)) , IntPropertyComboBox(*qtnCreateProperty(this)) , UIntProperty(*qtnCreateProperty(this)) , Int64Property(*qtnCreateProperty(this)) , UInt64Property(*qtnCreateProperty(this)) , Int64SliderBox(*qtnCreateProperty(this)) , UInt64SliderBox(*qtnCreateProperty(this)) , EnumProperty(*qtnCreateProperty(this)) , EnumFlagsProperty(*qtnCreateProperty(this)) , QStringValue(*qtnCreateProperty(this)) , EnableSubPropertySet(*qtnCreateProperty(this)) , SubPropertySet(*qtnCreateProperty(this)) , QPointProperty(*qtnCreateProperty(this)) , QSizeProperty(*qtnCreateProperty(this)) , QRectProperty(*qtnCreateProperty(this)) , QPointFProperty(*qtnCreateProperty(this)) , QSizeFProperty(*qtnCreateProperty(this)) , QRectFProperty(*qtnCreateProperty(this)) , QVector3DProperty(*qtnCreateProperty(this)) , QColorProperty(*qtnCreateProperty(this)) , QFontProperty(*qtnCreateProperty(this)) , FreqProperty(*qtnCreateProperty(this)) , LayerProperty(*qtnCreateProperty(this)) , BrushStyleProperty(*qtnCreateProperty(this)) , PenWidthProperty(*qtnCreateProperty(this)) , PenStyleProperty(*qtnCreateProperty(this)) , PenProperty(*qtnCreateProperty(this)) , QStringCallbackProperty(*qtnCreateProperty(this)) , SubPropertySet2(*qtnCreateProperty(this)) { init(); connectSlots(); connectDelegates(); } QtnPropertySetSamplePS::~QtnPropertySetSamplePS() { disconnectSlots(); } QtnPropertySetSamplePS& QtnPropertySetSamplePS::operator=(const QtnPropertySetSamplePS& other) { Q_UNUSED(other); myColor = other.myColor; BoolProperty = other.BoolProperty; ButtonProperty = other.ButtonProperty; ButtonLinkProperty = other.ButtonLinkProperty; RGBColor = other.RGBColor; ColorSolidDelegate = other.ColorSolidDelegate; FloatPropertySliderBox = other.FloatPropertySliderBox; FloatPercent = other.FloatPercent; DoublePercent = other.DoublePercent; FloatIntRangeSliderBox = other.FloatIntRangeSliderBox; DoubleFullRangeSliderBox = other.DoubleFullRangeSliderBox; DoubleProperty = other.DoubleProperty; FloatProperty = other.FloatProperty; IntProperty = other.IntProperty; IntPropertyComboBox = other.IntPropertyComboBox; UIntProperty = other.UIntProperty; Int64Property = other.Int64Property; UInt64Property = other.UInt64Property; Int64SliderBox = other.Int64SliderBox; UInt64SliderBox = other.UInt64SliderBox; EnumProperty = other.EnumProperty; EnumFlagsProperty = other.EnumFlagsProperty; QStringValue = other.QStringValue; EnableSubPropertySet = other.EnableSubPropertySet; SubPropertySet = other.SubPropertySet; QPointProperty = other.QPointProperty; QSizeProperty = other.QSizeProperty; QRectProperty = other.QRectProperty; QPointFProperty = other.QPointFProperty; QSizeFProperty = other.QSizeFProperty; QRectFProperty = other.QRectFProperty; QVector3DProperty = other.QVector3DProperty; QColorProperty = other.QColorProperty; QFontProperty = other.QFontProperty; FreqProperty = other.FreqProperty; LayerProperty = other.LayerProperty; BrushStyleProperty = other.BrushStyleProperty; PenWidthProperty = other.PenWidthProperty; PenStyleProperty = other.PenStyleProperty; PenProperty = other.PenProperty; QStringCallbackProperty = other.QStringCallbackProperty; SubPropertySet2 = other.SubPropertySet2; return *this; } QtnPropertySet* QtnPropertySetSamplePS::createNewImpl(QObject* parentForNew) const { return new QtnPropertySetSamplePS(parentForNew); } QtnPropertySet* QtnPropertySetSamplePS::createCopyImpl(QObject* parentForCopy) const { QtnPropertySetSamplePS* p = new QtnPropertySetSamplePS(parentForCopy); *p = *this; return p; } bool QtnPropertySetSamplePS::copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) { Q_UNUSED(ignoreMask); auto theCopyFrom = qobject_cast(propertySetCopyFrom); if (!theCopyFrom) return false; if (!(theCopyFrom->myColor.state() & ignoreMask)) { myColor = theCopyFrom->myColor; } if (!(theCopyFrom->BoolProperty.state() & ignoreMask)) { BoolProperty = theCopyFrom->BoolProperty; } if (!(theCopyFrom->ButtonProperty.state() & ignoreMask)) { ButtonProperty = theCopyFrom->ButtonProperty; } if (!(theCopyFrom->ButtonLinkProperty.state() & ignoreMask)) { ButtonLinkProperty = theCopyFrom->ButtonLinkProperty; } if (!(theCopyFrom->RGBColor.state() & ignoreMask)) { RGBColor = theCopyFrom->RGBColor; } if (!(theCopyFrom->ColorSolidDelegate.state() & ignoreMask)) { ColorSolidDelegate = theCopyFrom->ColorSolidDelegate; } if (!(theCopyFrom->FloatPropertySliderBox.state() & ignoreMask)) { FloatPropertySliderBox = theCopyFrom->FloatPropertySliderBox; } if (!(theCopyFrom->FloatPercent.state() & ignoreMask)) { FloatPercent = theCopyFrom->FloatPercent; } if (!(theCopyFrom->DoublePercent.state() & ignoreMask)) { DoublePercent = theCopyFrom->DoublePercent; } if (!(theCopyFrom->FloatIntRangeSliderBox.state() & ignoreMask)) { FloatIntRangeSliderBox = theCopyFrom->FloatIntRangeSliderBox; } if (!(theCopyFrom->DoubleFullRangeSliderBox.state() & ignoreMask)) { DoubleFullRangeSliderBox = theCopyFrom->DoubleFullRangeSliderBox; } if (!(theCopyFrom->DoubleProperty.state() & ignoreMask)) { DoubleProperty = theCopyFrom->DoubleProperty; } if (!(theCopyFrom->FloatProperty.state() & ignoreMask)) { FloatProperty = theCopyFrom->FloatProperty; } if (!(theCopyFrom->IntProperty.state() & ignoreMask)) { IntProperty = theCopyFrom->IntProperty; } if (!(theCopyFrom->IntPropertyComboBox.state() & ignoreMask)) { IntPropertyComboBox = theCopyFrom->IntPropertyComboBox; } if (!(theCopyFrom->UIntProperty.state() & ignoreMask)) { UIntProperty = theCopyFrom->UIntProperty; } if (!(theCopyFrom->Int64Property.state() & ignoreMask)) { Int64Property = theCopyFrom->Int64Property; } if (!(theCopyFrom->UInt64Property.state() & ignoreMask)) { UInt64Property = theCopyFrom->UInt64Property; } if (!(theCopyFrom->Int64SliderBox.state() & ignoreMask)) { Int64SliderBox = theCopyFrom->Int64SliderBox; } if (!(theCopyFrom->UInt64SliderBox.state() & ignoreMask)) { UInt64SliderBox = theCopyFrom->UInt64SliderBox; } if (!(theCopyFrom->EnumProperty.state() & ignoreMask)) { EnumProperty = theCopyFrom->EnumProperty; } if (!(theCopyFrom->EnumFlagsProperty.state() & ignoreMask)) { EnumFlagsProperty = theCopyFrom->EnumFlagsProperty; } if (!(theCopyFrom->QStringValue.state() & ignoreMask)) { QStringValue = theCopyFrom->QStringValue; } if (!(theCopyFrom->EnableSubPropertySet.state() & ignoreMask)) { EnableSubPropertySet = theCopyFrom->EnableSubPropertySet; } SubPropertySet.copyValues(&theCopyFrom->SubPropertySet, ignoreMask); if (!(theCopyFrom->QPointProperty.state() & ignoreMask)) { QPointProperty = theCopyFrom->QPointProperty; } if (!(theCopyFrom->QSizeProperty.state() & ignoreMask)) { QSizeProperty = theCopyFrom->QSizeProperty; } if (!(theCopyFrom->QRectProperty.state() & ignoreMask)) { QRectProperty = theCopyFrom->QRectProperty; } if (!(theCopyFrom->QPointFProperty.state() & ignoreMask)) { QPointFProperty = theCopyFrom->QPointFProperty; } if (!(theCopyFrom->QSizeFProperty.state() & ignoreMask)) { QSizeFProperty = theCopyFrom->QSizeFProperty; } if (!(theCopyFrom->QRectFProperty.state() & ignoreMask)) { QRectFProperty = theCopyFrom->QRectFProperty; } if (!(theCopyFrom->QVector3DProperty.state() & ignoreMask)) { QVector3DProperty = theCopyFrom->QVector3DProperty; } if (!(theCopyFrom->QColorProperty.state() & ignoreMask)) { QColorProperty = theCopyFrom->QColorProperty; } if (!(theCopyFrom->QFontProperty.state() & ignoreMask)) { QFontProperty = theCopyFrom->QFontProperty; } if (!(theCopyFrom->FreqProperty.state() & ignoreMask)) { FreqProperty = theCopyFrom->FreqProperty; } if (!(theCopyFrom->LayerProperty.state() & ignoreMask)) { LayerProperty = theCopyFrom->LayerProperty; } if (!(theCopyFrom->BrushStyleProperty.state() & ignoreMask)) { BrushStyleProperty = theCopyFrom->BrushStyleProperty; } if (!(theCopyFrom->PenWidthProperty.state() & ignoreMask)) { PenWidthProperty = theCopyFrom->PenWidthProperty; } if (!(theCopyFrom->PenStyleProperty.state() & ignoreMask)) { PenStyleProperty = theCopyFrom->PenStyleProperty; } if (!(theCopyFrom->PenProperty.state() & ignoreMask)) { PenProperty = theCopyFrom->PenProperty; } if (!(theCopyFrom->QStringCallbackProperty.state() & ignoreMask)) { QStringCallbackProperty = theCopyFrom->QStringCallbackProperty; } SubPropertySet2.copyValues(&theCopyFrom->SubPropertySet2, ignoreMask); return true; } void QtnPropertySetSamplePS::init() { static QString SamplePS_name = QStringLiteral("SamplePS"); setName(SamplePS_name); // start children initialization static QString myColor_name = QStringLiteral("myColor"); myColor.setName(myColor_name); static QString myColor_description = "Property to hold MyColor values."; myColor.setDescription(myColor_description); static QString BoolProperty_name = QStringLiteral("BoolProperty"); BoolProperty.setName(BoolProperty_name); static QString BoolProperty_description = "Property to hold boolean values."; BoolProperty.setDescription(BoolProperty_description); BoolProperty.setValue(false); static QString ButtonProperty_name = QStringLiteral("ButtonProperty"); ButtonProperty.setName(ButtonProperty_name); ButtonProperty.setClickHandler([](const QtnPropertyButton* bttn) { qDebug() << Q_FUNC_INFO << "Button has clicked: " << bttn; }); static QString ButtonProperty_description = "Start calculate a long operation."; ButtonProperty.setDescription(ButtonProperty_description); static QString ButtonLinkProperty_name = QStringLiteral("ButtonLinkProperty"); ButtonLinkProperty.setName(ButtonLinkProperty_name); ButtonLinkProperty.setClickHandler([](const QtnPropertyButton* bttn) { qDebug() << Q_FUNC_INFO << "Link has clicked: " << bttn; }); static QString RGBColor_name = QStringLiteral("RGBColor"); RGBColor.setName(RGBColor_name); RGBColor.setClickHandler([this](const QtnPropertyABColor* color) { qDebug() << Q_FUNC_INFO << "Color has clicked: " << color; RGBColor = QColor::fromRgb(qrand()%255, qrand()%255, qrand()%255); }); static QString RGBColor_description = "ABColor property with RGB components"; RGBColor.setDescription(RGBColor_description); RGBColor.setValue(QColor(123, 150, 10)); static QString ColorSolidDelegate_name = QStringLiteral("ColorSolidDelegate"); ColorSolidDelegate.setName(ColorSolidDelegate_name); static QString ColorSolidDelegate_description = "QColor property with Solid delegate"; ColorSolidDelegate.setDescription(ColorSolidDelegate_description); ColorSolidDelegate.setValue(QColor(13, 150, 10)); static QString FloatPropertySliderBox_name = QStringLiteral("FloatPropertySliderBox"); FloatPropertySliderBox.setName(FloatPropertySliderBox_name); static QString FloatPropertySliderBox_description = "Property to hold float values in range [0, 10]."; FloatPropertySliderBox.setDescription(FloatPropertySliderBox_description); FloatPropertySliderBox.setDisplayName("Float Property Slider Box"); FloatPropertySliderBox.setMaxValue(10.f); FloatPropertySliderBox.setMinValue(0); FloatPropertySliderBox.setStepValue(0.1f); FloatPropertySliderBox.setValue(1.f); static QString FloatPercent_name = QStringLiteral("FloatPercent"); FloatPercent.setName(FloatPercent_name); static QString FloatPercent_description = "Property to hold float values in range [0-1] visible as [0%-100%]."; FloatPercent.setDescription(FloatPercent_description); FloatPercent.setMaxValue(1.f); FloatPercent.setMinValue(0.f); FloatPercent.setValue(0.5f); static QString DoublePercent_name = QStringLiteral("DoublePercent"); DoublePercent.setName(DoublePercent_name); static QString DoublePercent_description = "Property to hold double values in range [0-1] visible as [0%-100%]."; DoublePercent.setDescription(DoublePercent_description); DoublePercent.setMaxValue(1.0); DoublePercent.setMinValue(0.0); DoublePercent.setValue(0.5); static QString FloatIntRangeSliderBox_name = QStringLiteral("FloatIntRangeSliderBox"); FloatIntRangeSliderBox.setName(FloatIntRangeSliderBox_name); static QString FloatIntRangeSliderBox_description = "Property to hold float values in full range."; FloatIntRangeSliderBox.setDescription(FloatIntRangeSliderBox_description); FloatIntRangeSliderBox.setMaxValue(float(1 << std::numeric_limits::digits)); FloatIntRangeSliderBox.setMinValue(-float(1 << std::numeric_limits::digits)); FloatIntRangeSliderBox.setValue(111.f); static QString DoubleFullRangeSliderBox_name = QStringLiteral("DoubleFullRangeSliderBox"); DoubleFullRangeSliderBox.setName(DoubleFullRangeSliderBox_name); static QString DoubleFullRangeSliderBox_description = "Property to hold double values in full range."; DoubleFullRangeSliderBox.setDescription(DoubleFullRangeSliderBox_description); DoubleFullRangeSliderBox.setMaxValue(double(1LL << std::numeric_limits::digits)); DoubleFullRangeSliderBox.setMinValue(-double(1LL << std::numeric_limits::digits)); DoubleFullRangeSliderBox.setValue(1111.0); static QString DoubleProperty_name = QStringLiteral("DoubleProperty"); DoubleProperty.setName(DoubleProperty_name); static QString DoubleProperty_description = "Property to hold double values in range [10, 20]."; DoubleProperty.setDescription(DoubleProperty_description); DoubleProperty.setMaxValue(20); DoubleProperty.setMinValue(10); DoubleProperty.setStepValue(0.5); DoubleProperty.setValue(12.3); static QString FloatProperty_name = QStringLiteral("FloatProperty"); FloatProperty.setName(FloatProperty_name); static QString FloatProperty_description = "Property to hold float values in range [-10, 0]."; FloatProperty.setDescription(FloatProperty_description); FloatProperty.setMaxValue(0); FloatProperty.setMinValue(-10); FloatProperty.setStepValue(0.5); FloatProperty.setValue(-3.5); static QString IntProperty_name = QStringLiteral("IntProperty"); IntProperty.setName(IntProperty_name); static QString IntProperty_description = "Property to hold integer values with changing step 15."; IntProperty.setDescription(IntProperty_description); IntProperty.setStepValue(15); IntProperty.setValue(10); static QString IntPropertyComboBox_name = QStringLiteral("IntPropertyComboBox"); IntPropertyComboBox.setName(IntPropertyComboBox_name); static QString IntPropertyComboBox_description = "Property to hold integer values with changing step 15."; IntPropertyComboBox.setDescription(IntPropertyComboBox_description); IntPropertyComboBox.setStepValue(15); IntPropertyComboBox.setValue(10); static QString UIntProperty_name = QStringLiteral("UIntProperty"); UIntProperty.setName(UIntProperty_name); static QString UIntProperty_description = "Property to hold unsigned integer values in range [100, 200]."; UIntProperty.setDescription(UIntProperty_description); UIntProperty.setMaxValue(200); UIntProperty.setMinValue(100); UIntProperty.setValue(100); static QString Int64Property_name = QStringLiteral("Int64Property"); Int64Property.setName(Int64Property_name); static QString Int64Property_description = "Property to hold signed integer 64-bit value"; Int64Property.setDescription(Int64Property_description); Int64Property.setValue(-(1LL << 35)); static QString UInt64Property_name = QStringLiteral("UInt64Property"); UInt64Property.setName(UInt64Property_name); static QString UInt64Property_description = "Property to hold signed integer 64-bit value"; UInt64Property.setDescription(UInt64Property_description); UInt64Property.setValue(1ULL << 63); static QString Int64SliderBox_name = QStringLiteral("Int64SliderBox"); Int64SliderBox.setName(Int64SliderBox_name); static QString Int64SliderBox_description = "Property to hold signed integer 64-bit value with slider box"; Int64SliderBox.setDescription(Int64SliderBox_description); Int64SliderBox.setValue(-(1LL << 34)); static QString UInt64SliderBox_name = QStringLiteral("UInt64SliderBox"); UInt64SliderBox.setName(UInt64SliderBox_name); static QString UInt64SliderBox_description = "Property to hold unsigned integer 64-bit value with slider box"; UInt64SliderBox.setDescription(UInt64SliderBox_description); UInt64SliderBox.setValue(1ULL << 58); static QString EnumProperty_name = QStringLiteral("EnumProperty"); EnumProperty.setName(EnumProperty_name); static QString EnumProperty_description = "Property to hold enum value (color)."; EnumProperty.setDescription(EnumProperty_description); EnumProperty.setEnumInfo(&COLOR::info()); EnumProperty.setValue(COLOR::red); static QString EnumFlagsProperty_name = QStringLiteral("EnumFlagsProperty"); EnumFlagsProperty.setName(EnumFlagsProperty_name); static QString EnumFlagsProperty_description = "Property to hold combination of enum values (options)."; EnumFlagsProperty.setDescription(EnumFlagsProperty_description); EnumFlagsProperty.setEnumInfo(&FLAGS::info()); EnumFlagsProperty.setValue(FLAGS::opt2); static QString QStringValue_name = QStringLiteral("QStringValue"); QStringValue.setName(QStringValue_name); static QString QStringValue_description = "Property to hold QString value."; QStringValue.setDescription(QStringValue_description); QStringValue.setValue("Hello world!"); static QString EnableSubPropertySet_name = QStringLiteral("EnableSubPropertySet"); EnableSubPropertySet.setName(EnableSubPropertySet_name); static QString EnableSubPropertySet_description = "Enable/Disable Sub-PropertySet."; EnableSubPropertySet.setDescription(EnableSubPropertySet_description); EnableSubPropertySet.setValue(false); static QString SubPropertySet_name = QStringLiteral("SubPropertySet"); SubPropertySet.setName(SubPropertySet_name); static QString SubPropertySet_description = "This property set is part of the root property set."; SubPropertySet.setDescription(SubPropertySet_description); SubPropertySet.setState(QtnPropertyStateImmutable); static QString QPointProperty_name = QStringLiteral("QPointProperty"); QPointProperty.setName(QPointProperty_name); static QString QPointProperty_description = "Property to hold QPoint value."; QPointProperty.setDescription(QPointProperty_description); QPointProperty.setValue(QPoint(-10, 10)); static QString QSizeProperty_name = QStringLiteral("QSizeProperty"); QSizeProperty.setName(QSizeProperty_name); static QString QSizeProperty_description = "Property to hold QSize value."; QSizeProperty.setDescription(QSizeProperty_description); QSizeProperty.setValue(QSize(100, 200)); static QString QRectProperty_name = QStringLiteral("QRectProperty"); QRectProperty.setName(QRectProperty_name); static QString QRectProperty_description = "Property to hold QRect value."; QRectProperty.setDescription(QRectProperty_description); QRectProperty.setValue(QRect(10, 10, 200, 200)); static QString QPointFProperty_name = QStringLiteral("QPointFProperty"); QPointFProperty.setName(QPointFProperty_name); static QString QPointFProperty_description = "Property to hold QPointF value."; QPointFProperty.setDescription(QPointFProperty_description); QPointFProperty.setValue(QPointF(-10.5, 10.2)); static QString QSizeFProperty_name = QStringLiteral("QSizeFProperty"); QSizeFProperty.setName(QSizeFProperty_name); static QString QSizeFProperty_description = "Property to hold QSizeF value."; QSizeFProperty.setDescription(QSizeFProperty_description); QSizeFProperty.setValue(QSizeF(100.0, 200.1)); static QString QRectFProperty_name = QStringLiteral("QRectFProperty"); QRectFProperty.setName(QRectFProperty_name); static QString QRectFProperty_description = "Property to hold QRectF value."; QRectFProperty.setDescription(QRectFProperty_description); QRectFProperty.setValue(QRectF(10.23, 10.4, 200.2, 200.6)); static QString QVector3DProperty_name = QStringLiteral("QVector3DProperty"); QVector3DProperty.setName(QVector3DProperty_name); static QString QVector3DProperty_description = "Property to hold QVector3D value."; QVector3DProperty.setDescription(QVector3DProperty_description); QVector3DProperty.setValue(QVector3D(5, 6, 7)); static QString QColorProperty_name = QStringLiteral("QColorProperty"); QColorProperty.setName(QColorProperty_name); static QString QColorProperty_description = "Property to hold QColor value."; QColorProperty.setDescription(QColorProperty_description); QColorProperty.setValue(Qt::blue); static QString QFontProperty_name = QStringLiteral("QFontProperty"); QFontProperty.setName(QFontProperty_name); static QString QFontProperty_description = "Property to hold QFont value."; QFontProperty.setDescription(QFontProperty_description); QFontProperty.setValue(QFont("Sans Serif", 14)); static QString FreqProperty_name = QStringLiteral("FreqProperty"); FreqProperty.setName(FreqProperty_name); static QString FreqProperty_description = "Property to hold frequency values."; FreqProperty.setDescription(FreqProperty_description); FreqProperty.setUnit(FreqUnit::KHz); FreqProperty.setValue(15); static QString LayerProperty_name = QStringLiteral("LayerProperty"); LayerProperty.setName(LayerProperty_name); static QString LayerProperty_description = "Property to hold layer."; LayerProperty.setDescription(LayerProperty_description); LayerProperty.setValue(0); static QString BrushStyleProperty_name = QStringLiteral("BrushStyleProperty"); BrushStyleProperty.setName(BrushStyleProperty_name); static QString BrushStyleProperty_description = "Property to hold QBrushStyle enum."; BrushStyleProperty.setDescription(BrushStyleProperty_description); BrushStyleProperty.setValue(Qt::HorPattern); static QString PenWidthProperty_name = QStringLiteral("PenWidthProperty"); PenWidthProperty.setName(PenWidthProperty_name); static QString PenWidthProperty_description = "Property to hold PenWidth enum."; PenWidthProperty.setDescription(PenWidthProperty_description); PenWidthProperty.setValue(PenWidth::Middle); static QString PenStyleProperty_name = QStringLiteral("PenStyleProperty"); PenStyleProperty.setName(PenStyleProperty_name); static QString PenStyleProperty_description = "Property to hold pen style values."; PenStyleProperty.setDescription(PenStyleProperty_description); PenStyleProperty.setValue(Qt::DashLine); static QString PenProperty_name = QStringLiteral("PenProperty"); PenProperty.setName(PenProperty_name); static QString PenProperty_description = "Property to hold QPen values."; PenProperty.setDescription(PenProperty_description); static QString QStringCallbackProperty_name = QStringLiteral("QStringCallbackProperty"); QStringCallbackProperty.setName(QStringCallbackProperty_name); static QString QStringCallbackProperty_description = "Property to hold QString values with candidates."; QStringCallbackProperty.setDescription(QStringCallbackProperty_description); static QString SubPropertySet2_name = QStringLiteral("SubPropertySet2"); SubPropertySet2.setName(SubPropertySet2_name); SubPropertySet2.setState(QtnPropertyStateCollapsed); // end children initialization } void QtnPropertySetSamplePS::connectSlots() { QObject::connect(&EnableSubPropertySet, &QtnProperty::propertyDidChange, this, &QtnPropertySetSamplePS::on_EnableSubPropertySet_propertyDidChange); QObject::connect(&QColorProperty, &QtnProperty::propertyDidChange, this, &QtnPropertySetSamplePS::on_QColorProperty_propertyDidChange); } void QtnPropertySetSamplePS::disconnectSlots() { QObject::disconnect(&EnableSubPropertySet, &QtnProperty::propertyDidChange, this, &QtnPropertySetSamplePS::on_EnableSubPropertySet_propertyDidChange); QObject::disconnect(&QColorProperty, &QtnProperty::propertyDidChange, this, &QtnPropertySetSamplePS::on_QColorProperty_propertyDidChange); } void QtnPropertySetSamplePS::on_EnableSubPropertySet_propertyDidChange(QtnPropertyChangeReason reason) { Q_UNUSED(reason); SubPropertySet.switchState(QtnPropertyStateImmutable, !EnableSubPropertySet); } void QtnPropertySetSamplePS::on_QColorProperty_propertyDidChange(QtnPropertyChangeReason reason) { Q_UNUSED(reason); qDebug() << Q_FUNC_INFO << "Property has changed: " << &QColorProperty; } void QtnPropertySetSamplePS::connectDelegates() { ButtonProperty.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.attributes["title"] = "Click me"; return info; }); ButtonLinkProperty.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "Link"; info.attributes["title"] = "Click on me"; return info; }); RGBColor.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.attributes["rgbSubItems"] = true; return info; }); ColorSolidDelegate.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "Solid"; return info; }); FloatPropertySliderBox.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "SliderBox"; info.attributes["drawBorder"] = false; info.attributes["fillColor"] = QColor::fromRgb(170, 170, 255); return info; }); FloatPercent.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.attributes["multiplier"] = 100.0; info.attributes["suffix"] = "%"; return info; }); DoublePercent.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.attributes["multiplier"] = 100.0; info.attributes["precision"] = 10; info.attributes["suffix"] = "%"; return info; }); FloatIntRangeSliderBox.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "SliderBox"; info.attributes["drawBorder"] = false; info.attributes["fillColor"] = QColor::fromRgb(170, 170, 255); return info; }); DoubleFullRangeSliderBox.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "SliderBox"; info.attributes["drawBorder"] = false; info.attributes["fillColor"] = QColor::fromRgb(170, 170, 255); return info; }); IntPropertyComboBox.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "IntList"; info.attributes["values"] = QVariant::fromValue(QList() << 10 << 12 << 15); return info; }); Int64Property.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.attributes["step"] = 100000; return info; }); Int64SliderBox.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "SliderBox"; return info; }); UInt64SliderBox.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "SliderBox"; return info; }); QVector3DProperty.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.attributes["max"] = 255; info.attributes["min"] = 0; info.attributes["multiplier"] = 100.0 / 255.0; info.attributes["precision"] = 5; info.attributes["suffix"] = "%"; info.attributes["z"] = QVariantMap({ { QString("name"), QString("SliderBox")}, { QString("precision"), 3 }, }); return info; }); PenProperty.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.attributes["editColor"] = true; info.attributes["editStyle"] = true; info.attributes["editWidth"] = true; return info; }); } ================================================ FILE: Demo/Demo.peg.h ================================================ #ifndef DEMO_H #define DEMO_H #include "QtnProperty/PropertyCore.h" #include "QtnProperty/PropertyGUI.h" #include "QtnProperty/PropertyInt64.h" #include "QtnProperty/PropertyUInt64.h" #include "AB/PropertyABColor.h" #include "Layer/PropertyLayer.h" #include "PenWidth/PropertyPenWidth.h" #include "Freq/PropertyFreq.h" class COLOR { public: enum Enum { red = 1, blue = 2, green = 3 }; static const QtnEnumInfo& info(); static const unsigned int values_count = 3; }; class FLAGS { public: enum Enum { opt1 = 1, opt2 = 2, opt3 = 4 }; static const QtnEnumInfo& info(); static const unsigned int values_count = 3; }; class QtnPropertySetSubPropertySetType: public QtnPropertySet { Q_OBJECT //Q_DISABLE_COPY(QtnPropertySetSubPropertySetType) public: // constructor declaration explicit QtnPropertySetSubPropertySetType(QObject* parent = nullptr); // destructor declaration virtual ~QtnPropertySetSubPropertySetType() override; // assignment declaration QtnPropertySetSubPropertySetType& operator=(const QtnPropertySetSubPropertySetType& other); // start children declarations QtnPropertyBool& SwitchProperty; QtnPropertyQStringCallback& ReadOnlyString; QtnPropertyQString& FileNameProperty; QtnPropertyQString& FolderNameProperty; QtnPropertyQString& StringFromList; QtnPropertyQColor& CircleShapeColor; // end children declarations protected: // cloning implementation QtnPropertySet* createNewImpl(QObject* parentForNew) const override; QtnPropertySet* createCopyImpl(QObject* parentForCopy) const override; // copy values implementation bool copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) override; private: void init(); void connectSlots(); void disconnectSlots(); void connectDelegates(); }; class QtnPropertySetSamplePS: public QtnPropertySet { Q_OBJECT //Q_DISABLE_COPY(QtnPropertySetSamplePS) public: // constructor declaration explicit QtnPropertySetSamplePS(QObject* parent = nullptr); // destructor declaration virtual ~QtnPropertySetSamplePS() override; // assignment declaration QtnPropertySetSamplePS& operator=(const QtnPropertySetSamplePS& other); // start children declarations QtnPropertyMyColor& myColor; QtnPropertyBool& BoolProperty; QtnPropertyButton& ButtonProperty; QtnPropertyButton& ButtonLinkProperty; QtnPropertyABColor& RGBColor; QtnPropertyQColor& ColorSolidDelegate; QtnPropertyFloat& FloatPropertySliderBox; QtnPropertyFloat& FloatPercent; QtnPropertyDouble& DoublePercent; QtnPropertyFloat& FloatIntRangeSliderBox; QtnPropertyDouble& DoubleFullRangeSliderBox; QtnPropertyDouble& DoubleProperty; QtnPropertyFloat& FloatProperty; QtnPropertyInt& IntProperty; QtnPropertyInt& IntPropertyComboBox; QtnPropertyUInt& UIntProperty; QtnPropertyInt64& Int64Property; QtnPropertyUInt64& UInt64Property; QtnPropertyInt64& Int64SliderBox; QtnPropertyUInt64& UInt64SliderBox; QtnPropertyEnum& EnumProperty; QtnPropertyEnumFlags& EnumFlagsProperty; QtnPropertyQString& QStringValue; QtnPropertyBool& EnableSubPropertySet; QtnPropertySetSubPropertySetType& SubPropertySet; QtnPropertyQPoint& QPointProperty; QtnPropertyQSize& QSizeProperty; QtnPropertyQRect& QRectProperty; QtnPropertyQPointF& QPointFProperty; QtnPropertyQSizeF& QSizeFProperty; QtnPropertyQRectF& QRectFProperty; QtnPropertyQVector3D& QVector3DProperty; QtnPropertyQColor& QColorProperty; QtnPropertyQFont& QFontProperty; QtnPropertyFreq& FreqProperty; QtnPropertyLayer& LayerProperty; QtnPropertyQBrushStyle& BrushStyleProperty; QtnPropertyPenWidth& PenWidthProperty; QtnPropertyQPenStyle& PenStyleProperty; QtnPropertyQPen& PenProperty; QtnPropertyQString& QStringCallbackProperty; QtnPropertySetSubPropertySetType& SubPropertySet2; // end children declarations protected: // cloning implementation QtnPropertySet* createNewImpl(QObject* parentForNew) const override; QtnPropertySet* createCopyImpl(QObject* parentForCopy) const override; // copy values implementation bool copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) override; private: void init(); void connectSlots(); void disconnectSlots(); void connectDelegates(); // start slot declarations void on_EnableSubPropertySet_propertyDidChange(QtnPropertyChangeReason reason); void on_QColorProperty_propertyDidChange(QtnPropertyChangeReason reason); // end slot declarations }; #endif // DEMO_H ================================================ FILE: Demo/Demo.pro ================================================ include(../QtnPropertyDepend.pri) include(../Internal/TargetConfig.pri) include(../PEG/PEG.pri) QT += core gui widgets script scripttools TARGET = QtnPropertyDemo TEMPLATE = app SOURCES += main.cpp\ MainWindow.cpp \ mydialog.cpp \ AB/PropertyABColor.cpp \ AB/PropertyDelegateABColor.cpp \ Int/PropertyDelegateIntList.cpp \ Layer/PropertyLayer.cpp \ Layer/PropertyDelegateLayer.cpp \ PenWidth/PropertyPenWidth.cpp \ PenWidth/PropertyDelegatePenWidth.cpp \ Freq/PropertyFreq.cpp \ Freq/PropertyDelegateFreq.cpp HEADERS += MainWindow.h \ mydialog.h \ AB/PropertyABColor.h \ AB/PropertyDelegateABColor.h \ Int/PropertyDelegateIntList.h \ Layer/PropertyLayer.h \ Layer/PropertyDelegateLayer.h \ PenWidth/PropertyPenWidth.h \ PenWidth/PropertyDelegatePenWidth.h \ Freq/PropertyFreq.h \ Freq/PropertyDelegateFreq.h FORMS += MainWindow.ui \ mydialog.ui PEG_SOURCES += Demo.pef OTHER_FILES += \ Demo.pef QMAKE_BUNDLE_DATA += DYNAMIC_LIBS unix:QMAKE_LFLAGS += -Wl,-rpath,\'\$$ORIGIN\' ================================================ FILE: Demo/Freq/PropertyDelegateFreq.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateFreq.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "PropertyFreq.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include #include #include #include void regFreqDelegates() { QtnPropertyDelegateFactory::staticInstance().registerDelegateDefault( &QtnPropertyFreqBase::staticMetaObject, &qtnCreateDelegate); } static QString freqUnit2Str(FreqUnit unit) { switch (unit) { case FreqUnit::Hz: return "Hz"; case FreqUnit::KHz: return "KHz"; case FreqUnit::MHz: return "MHz"; default: return "NA"; } } void QtnPropertyDelegateFreq::createSubItemValuesImpl( QtnDrawContext &context, const QRect &rect, QList &subItems) { auto unitWidth = context.painter->fontMetrics().width("MHz"); auto spaceWidth = context.painter->fontMetrics().width(" "); auto valueRect = rect; valueRect.setRight(valueRect.right() - unitWidth - spaceWidth); auto unitRect = rect; unitRect.setLeft(valueRect.right() + spaceWidth); if (valueRect.isValid()) addValueSubItem(context, valueRect, subItems); if (unitRect.isValid()) addUnitSubItem(context, unitRect, subItems); } void QtnPropertyDelegateFreq::addValueSubItem(QtnDrawContext & /*context*/, const QRect &rect, QList &subItems) { QtnSubItem subItem(rect); subItem.drawHandler = [this]( QtnDrawContext &context, const QtnSubItem &item) { auto text = qtnElidedText(*context.painter, QString::number(owner().value()), item.rect, nullptr); context.painter->drawText( item.rect, Qt::AlignRight | Qt::AlignVCenter, text); }; subItems.append(subItem); } void QtnPropertyDelegateFreq::addUnitSubItem(QtnDrawContext & /*context*/, const QRect &rect, QList &subItems) { QtnSubItem subItem(rect); subItem.drawHandler = [this]( QtnDrawContext &context, const QtnSubItem &item) { qtnDrawValueText(freqUnit2Str(owner().unit()), *context.painter, item.rect, context.style()); }; subItems.append(subItem); } ================================================ FILE: Demo/Freq/PropertyDelegateFreq.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_FREQ_H #define PROPERTY_DELEGATE_FREQ_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" class QtnPropertyFreqBase; class QtnPropertyDelegateFreq : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateFreq) public: QtnPropertyDelegateFreq(QtnPropertyFreqBase &owner) : QtnPropertyDelegateTyped(owner) { } protected: void createSubItemValuesImpl(QtnDrawContext &context, const QRect &rect, QList &subItems) override; private: void addValueSubItem(QtnDrawContext &context, const QRect &rect, QList &subItems); void addUnitSubItem(QtnDrawContext &context, const QRect &rect, QList &subItems); }; #endif // PROPERTY_DELEGATE_FREQ_H ================================================ FILE: Demo/Freq/PropertyFreq.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyFreq.h" void QtnPropertyFreqBase::setUnit(FreqUnit unit) { if (m_unit == unit) return; Q_EMIT propertyWillChange(QtnPropertyChangeReasonValue, &unit, 0); m_unit = unit; Q_EMIT propertyDidChange(QtnPropertyChangeReasonValue); } bool QtnPropertyFreqBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { Q_UNUSED(str); Q_UNUSED(reason); return false; } bool QtnPropertyFreqBase::toStrImpl(QString &str) const { Q_UNUSED(str); return false; } ================================================ FILE: Demo/Freq/PropertyFreq.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_FREQ_H #define PROPERTY_FREQ_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" enum class FreqUnit { Hz, KHz, MHz }; class QtnPropertyFreqBase : public QtnSinglePropertyBase { Q_OBJECT QtnPropertyFreqBase(const QtnPropertyFreqBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyFreqBase(QObject *parent) : QtnSinglePropertyBase(parent) , m_unit(FreqUnit::Hz) { } FreqUnit unit() const { return m_unit; } void setUnit(FreqUnit unit); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; private: FreqUnit m_unit; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyFreqBase) }; class QtnPropertyFreqCallback : public QtnSinglePropertyCallback { Q_OBJECT QtnPropertyFreqCallback( const QtnPropertyFreqCallback &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyFreqCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyFreqCallback, QtnPropertyFreqBase) }; class QtnPropertyFreq : public QtnSinglePropertyValue { Q_OBJECT QtnPropertyFreq(const QtnPropertyFreq &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyFreq(QObject *parent) : QtnSinglePropertyValue(parent) { } P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyFreq, QtnPropertyFreqBase) }; #endif // PROPERTY_FREQ_H ================================================ FILE: Demo/Int/PropertyDelegateIntList.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateIntList.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Core/PropertyInt.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include void regIntListDelegates() { QtnPropertyDelegateFactory::staticInstance().registerDelegate( &QtnPropertyIntBase::staticMetaObject, &qtnCreateDelegate, "IntList"); } class QtnPropertyIntComboBoxHandler : public QtnPropertyEditorHandlerVT { public: QtnPropertyIntComboBoxHandler( QtnPropertyDelegateIntList *delegate, QComboBox &editor) : QtnPropertyEditorHandlerVT(delegate, editor) { updateEditor(); QObject::connect(&editor, static_cast( &QComboBox::currentIndexChanged), this, &QtnPropertyIntComboBoxHandler::onCurrentIndexChanged); } private: void updateEditor() override { updating++; editor().setEnabled(stateProperty()->isEditableByUser()); if (stateProperty()->isMultiValue()) editor().setCurrentIndex(-1); else { int index = editor().findData((int) property()); editor().setCurrentIndex(index); } updating--; } void onCurrentIndexChanged(int index) { if (index >= 0) { QVariant data = editor().itemData(index); if (data.canConvert()) onValueChanged(data.toInt()); } } }; QtnPropertyDelegateIntList::QtnPropertyDelegateIntList( QtnPropertyIntBase &owner) : QtnPropertyDelegateInt(owner) { } QWidget *QtnPropertyDelegateIntList::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { QComboBox *comboBox = new QtnPropertyComboBox(this, parent); auto delegate = owner().delegateInfo(); if (delegate) { QList values; delegate->loadAttribute("values", values); for (auto value : values) { comboBox->addItem(QString::number(value), value); } } comboBox->setGeometry(rect); // connect widget and property new QtnPropertyIntComboBoxHandler(this, *comboBox); if (inplaceInfo && stateProperty()->isEditableByUser()) comboBox->showPopup(); return comboBox; } ================================================ FILE: Demo/Int/PropertyDelegateIntList.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_INT_LIST_H #define PROPERTY_DELEGATE_INT_LIST_H #include "QtnProperty/Delegates/Core/PropertyDelegateInt.h" class QtnPropertyIntBase; class QtnPropertyDelegateIntList : public QtnPropertyDelegateInt { Q_DISABLE_COPY(QtnPropertyDelegateIntList) public: QtnPropertyDelegateIntList(QtnPropertyIntBase &owner); protected: QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; }; #endif // PROPERTY_DELEGATE_INT_LIST_H ================================================ FILE: Demo/Layer/PropertyDelegateLayer.cpp ================================================ /* Copyright (c) 2012-2016 Alex Zhondin Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include "PropertyDelegateLayer.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "PropertyLayer.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include #include #include #include void regLayerDelegates() { QtnPropertyDelegateFactory::staticInstance().registerDelegateDefault( &QtnPropertyLayerBase::staticMetaObject, &qtnCreateDelegate); } static void drawLayer( QStyle *style, const LayerInfo &layer, QPainter &painter, const QRect &rect) { QRect textRect = rect; QRect colorRect = rect; colorRect.setWidth(colorRect.height()); colorRect.adjust(2, 2, -2, -2); painter.fillRect(colorRect, Qt::black); colorRect.adjust(1, 1, -1, -1); painter.fillRect(colorRect, layer.color); textRect.setLeft(colorRect.right() + 5); if (textRect.isValid()) { qtnDrawValueText(layer.name, painter, textRect, style); } } class QtnPropertyLayerComboBox : public QComboBox { public: explicit QtnPropertyLayerComboBox( QtnPropertyDelegateLayer *delegate, QWidget *parent = Q_NULLPTR) : QComboBox(parent) , m_delegate(delegate) , m_property(static_cast(delegate->property())) , m_updating(0) { m_layers = m_property->layers(); setLineEdit(nullptr); setItemDelegate(new ItemDelegate(m_layers, this)); for (const auto &layer : m_layers) { Q_UNUSED(layer); addItem(QString()); } updateEditor(); QObject::connect(m_property, &QtnPropertyBase::propertyDidChange, this, &QtnPropertyLayerComboBox::onPropertyDidChange); QObject::connect(this, static_cast( &QComboBox::currentIndexChanged), this, &QtnPropertyLayerComboBox::onCurrentIndexChanged); } protected: void paintEvent(QPaintEvent *event) override { QComboBox::paintEvent(event); QPainter painter(this); auto index = currentIndex(); if (index != -1) { Q_ASSERT(index < m_layers.size()); drawLayer(style(), m_layers[index], painter, event->rect()); } } void updateEditor() { m_updating++; setEnabled(m_delegate->stateProperty()->isEditableByUser()); setCurrentIndex(m_property->value()); m_updating--; } void onPropertyDidChange(QtnPropertyChangeReason reason) { if ((reason & QtnPropertyChangeReasonValue)) updateEditor(); } void onCurrentIndexChanged(int index) { if (m_updating) return; if (index >= 0) { Q_ASSERT(index < m_layers.size()); m_property->setValue(index, m_delegate->editReason()); } } private: QtnPropertyDelegateLayer *m_delegate; QtnPropertyLayerBase *m_property; QList m_layers; unsigned m_updating; class ItemDelegate : public QStyledItemDelegate { public: ItemDelegate(const QList &layers, QComboBox *owner) : m_layers(layers) , m_owner(owner) { } void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { QStyledItemDelegate::paint(painter, option, index); Q_ASSERT(index.row() < m_layers.size()); drawLayer( m_owner->style(), m_layers[index.row()], *painter, option.rect); } private: const QList &m_layers; QComboBox *m_owner; }; }; void QtnPropertyDelegateLayer::drawValueImpl( QStylePainter &painter, const QRect &rect) const { auto layer = owner().valueLayer(); if (layer) drawLayer(painter.style(), *layer, painter, rect); } QWidget *QtnPropertyDelegateLayer::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { auto combo = new QtnPropertyLayerComboBox(this, parent); combo->setGeometry(rect); if (inplaceInfo && stateProperty()->isEditableByUser()) combo->showPopup(); return combo; } ================================================ FILE: Demo/Layer/PropertyDelegateLayer.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_LAYER_H #define PROPERTY_DELEGATE_LAYER_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" class QtnPropertyLayerBase; class QtnPropertyDelegateLayer : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateLayer) public: QtnPropertyDelegateLayer(QtnPropertyLayerBase &owner) : QtnPropertyDelegateTyped(owner) { } protected: void drawValueImpl( QStylePainter &painter, const QRect &rect) const override; QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; }; #endif // PROPERTY_DELEGATE_LAYER_H ================================================ FILE: Demo/Layer/PropertyLayer.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyLayer.h" const LayerInfo *QtnPropertyLayerBase::valueLayer() const { const auto &layerValues = layers(); auto layerIndex = value(); if (layerIndex < 0 || layerIndex >= layerValues.size()) return nullptr; return &layerValues[layerIndex]; } LayerInfo *QtnPropertyLayerBase::valueLayer() { return const_cast( ((const QtnPropertyLayerBase *) this)->valueLayer()); } const QList &QtnPropertyLayerBase::layers() const { return m_layers; } void QtnPropertyLayerBase::setLayers(QList layers) { Q_EMIT propertyWillChange(QtnPropertyChangeReasonValue, nullptr, 0); m_layers = layers; Q_EMIT propertyDidChange(QtnPropertyChangeReasonValue); } bool QtnPropertyLayerBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { int index = 0; for (const auto &layer : layers()) { if (layer.name == str) { return setValue(index, reason); } ++index; } return false; } bool QtnPropertyLayerBase::toStrImpl(QString &str) const { auto layer = valueLayer(); if (layer) str = layer->name; return true; } ================================================ FILE: Demo/Layer/PropertyLayer.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_LAYER_H #define PROPERTY_LAYER_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include struct LayerInfo { QString name; QColor color; qintptr data = 0; LayerInfo() {} LayerInfo(QString name, QColor color, qintptr data = 0) : name(name) , color(color) , data(data) { } }; /* inline bool operator== (const LayerInfo& left, const LayerInfo& right) { return left.name == right.name; } inline bool operator != (const LayerInfo& left, const LayerInfo& right) { return !(left == right); } QDataStream& operator<< (QDataStream& stream, const LayerInfo& layer); QDataStream& operator>> (QDataStream& stream, LayerInfo& layer); Q_DECLARE_METATYPE(LayerInfo) */ class QtnPropertyLayerBase : public QtnSinglePropertyBase { Q_OBJECT QtnPropertyLayerBase(const QtnPropertyLayerBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyLayerBase(QObject *parent) : QtnSinglePropertyBase(parent) { } const LayerInfo *valueLayer() const; LayerInfo *valueLayer(); const QList &layers() const; void setLayers(QList layers); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; private: QList m_layers; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyLayerBase) }; class QtnPropertyLayerCallback : public QtnSinglePropertyCallback { Q_OBJECT QtnPropertyLayerCallback( const QtnPropertyLayerCallback &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyLayerCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyLayerCallback, QtnPropertyLayerBase) }; class QtnPropertyLayer : public QtnSinglePropertyValue { Q_OBJECT QtnPropertyLayer(const QtnPropertyLayer &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyLayer(QObject *parent) : QtnSinglePropertyValue(parent) { } P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyLayer, QtnPropertyLayerBase) }; #endif // PROPERTY_LAYER_H ================================================ FILE: Demo/MainWindow.cpp ================================================ #include "MainWindow.h" #include "ui_MainWindow.h" #include "mydialog.h" #include #include #include #include "QtnProperty/QObjectPropertySet.h" #include "Demo.peg.h" #include "QtnProperty/FunctionalHelpers.h" // this is required for QStringCallbackProperty delegate parameters #include "QtnProperty/Delegates/Core/PropertyDelegateQString.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , m_candidates({ "one", "two", "three" }) { ui->setupUi(this); ui->pw->setParts(QtnPropertyWidgetPartsDescriptionPanel); auto ps = new QtnPropertySetSamplePS(this); ps->LayerProperty.setLayers( { { "Top", Qt::red, 0 }, { "Left", Qt::blue, 1 }, { "Right", Qt::green, 2 }, { "Bottom", Qt::gray, 3 } }); ps->QStringCallbackProperty.setDelegateInfo({ "Callback" }); QVariant attr; attr.setValue(qtnMemFn(this, &MainWindow::getCandidates)); ps->QStringCallbackProperty.setDelegateAttribute("GetCandidatesFn", attr); attr.setValue(qtnMemFn(this, &MainWindow::createCandidate)); ps->QStringCallbackProperty.setDelegateAttribute("CreateCandidateFn", attr); ui->pw->setPropertySet(ps); qtnScriptRegisterPropertyTypes(&jsEngine); jsEngine.globalObject().setProperty("samplePS", jsEngine.newQObject(ps)); dbg.attachTo(&jsEngine); move(QApplication::desktop()->availableGeometry().center() - rect().center()); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_editButton_clicked() { QtnPropertySet *properties = ui->pw->propertySet(); if (!properties) { QMessageBox::warning(this, "Demo", "Property is not set."); return; } // copy of properties QtnPropertySet *cpy = properties->createCopy(this); Q_ASSERT(cpy); // defaults QtnPropertySet *dft = properties->createNew(this); MyDialog dlg(this, *cpy, dft); if (dlg.exec() == QDialog::Accepted) { properties->copyValues( cpy, QtnPropertyStateImmutable | QtnPropertyStateInvisible); } } void MainWindow::on_dbgButton_clicked() { QMainWindow *dbgWindow = dbg.standardWindow(); dbgWindow->show(); } void MainWindow::on_pushButton_clicked() { QtnPropertySet *properties = ui->pw->propertySet(); if (!properties) { QMessageBox::warning(this, "Demo", "Property is not set."); return; } QString txt = ui->plainTextEdit->toPlainText(); if (!properties->fromStr(txt)) { QMessageBox::warning( this, "Demo", "Cannot apply string to Propertyset."); return; } ui->plainTextEdit->clear(); } void MainWindow::on_pushButton_3_clicked() { QtnPropertySet *properties = ui->pw->propertySet(); if (!properties) { QMessageBox::warning(this, "Demo", "Property is not set."); return; } QString text; if (!properties->toStr(text)) { QMessageBox::warning( this, "Demo", "Cannot get string from Propertyset."); return; } ui->plainTextEdit->setPlainText(text); } void MainWindow::on_pushButton_2_clicked() { QtnPropertySet *bttnProperties = qtnCreateQObjectPropertySet(ui->pushButton_2); QtnPropertySet *editProperties = qtnCreateQObjectPropertySet(ui->plainTextEdit); QtnPropertySet properties(this); if (bttnProperties) properties.addChildProperty(bttnProperties); if (editProperties) properties.addChildProperty(editProperties); MyDialog dlg(this, properties); dlg.exec(); } QString MainWindow::createCandidate(QWidget *parent, QString candidate) { bool ok; QString text = QInputDialog::getText( parent, "Create item", "Name:", QLineEdit::Normal, candidate, &ok); if (ok && !text.isEmpty()) { if (m_candidates.indexOf(text) < 0) m_candidates.append(text); else QMessageBox::warning( parent, "Create item", "Cannot create duplicate."); return text; } return QString(); } ================================================ FILE: Demo/MainWindow.h ================================================ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include "QtnProperty/Property.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void on_editButton_clicked(); void on_dbgButton_clicked(); void on_pushButton_clicked(); void on_pushButton_2_clicked(); void on_pushButton_3_clicked(); private: QStringList getCandidates() const { return m_candidates; } QString createCandidate(QWidget *parent, QString candidate); Ui::MainWindow *ui; QScriptEngineDebugger dbg; QScriptEngine jsEngine; QStringList m_candidates; }; #endif // MAINWINDOW_H ================================================ FILE: Demo/MainWindow.ui ================================================ MainWindow true 0 0 675 468 10 PropertyWidget Demo 24 24 0 0 0 0 150 0 Edit in modal dialog... 0 0 Script examples: samplePS.IntProperty.value = 15; print(samplePS.SubPropertySet.SwitchProperty.state); samplePS.UIntProperty.propertyDidChange.connect( function(p1, p2) { print(p2.name+" is "+p2.value+" now"); }); Qt::PlainText true Show script debugger String examples: EnumProperty = blue EnableSubPropertySet = true SubPropertySet.FolderNameProperty = "/home/my" Qt::PlainText from string to string edit QObject properties Qt::Vertical 20 40 QtnPropertyWidget QWidget
QtnProperty/PropertyWidget.h
1
================================================ FILE: Demo/PenWidth/PropertyDelegatePenWidth.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegatePenWidth.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "PropertyPenWidth.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include #include #include #include void regPenWidthDelegates() { QtnPropertyDelegateFactory::staticInstance().registerDelegateDefault( &QtnPropertyPenWidthBase::staticMetaObject, &qtnCreateDelegate); } static void drawPenWidth( QStyle *style, PenWidth penWidth, QPainter &painter, QRect rect) { rect.adjust(2, 2, -2, -2); QPen pen = painter.pen(); switch (penWidth) { case PenWidth::Default: qtnDrawValueText("Default", painter, rect, style); return; case PenWidth::Thin: pen.setWidth(1); break; case PenWidth::Middle: pen.setWidth(2); break; case PenWidth::Thick: pen.setWidth(3); break; } painter.save(); painter.setPen(pen); auto midY = rect.center().y(); painter.drawLine(rect.left(), midY, rect.right(), midY); painter.restore(); } class QtnPropertyPenWidthComboBox : public QComboBox { public: explicit QtnPropertyPenWidthComboBox( QtnPropertyDelegatePenWidth *delegate, QWidget *parent = Q_NULLPTR) : QComboBox(parent) , m_delegate(delegate) , m_property( *static_cast(delegate->property())) , m_updating(0) { setLineEdit(nullptr); setItemDelegate(new ItemDelegate(this)); addItem(QString(), QVariant::fromValue(PenWidth::Default)); addItem(QString(), QVariant::fromValue(PenWidth::Thin)); addItem(QString(), QVariant::fromValue(PenWidth::Middle)); addItem(QString(), QVariant::fromValue(PenWidth::Thick)); updateEditor(); QObject::connect(&m_property, &QtnPropertyBase::propertyDidChange, this, &QtnPropertyPenWidthComboBox::onPropertyDidChange, Qt::QueuedConnection); QObject::connect(this, static_cast( &QComboBox::currentIndexChanged), this, &QtnPropertyPenWidthComboBox::onCurrentIndexChanged); } protected: void paintEvent(QPaintEvent *event) override { QComboBox::paintEvent(event); QPainter painter(this); auto index = currentIndex(); if (index != -1) { auto penWidth = currentData().value(); drawPenWidth(style(), penWidth, painter, event->rect().adjusted(0, 0, -event->rect().height(), 0)); } } void updateEditor() { m_updating++; setEnabled(m_delegate->stateProperty()->isEditableByUser()); for (int i = 0; i < count(); ++i) { if (itemData(i).value() == m_property.value()) setCurrentIndex(i); } m_updating--; } void onPropertyDidChange(QtnPropertyChangeReason reason) { if ((reason & QtnPropertyChangeReasonValue)) updateEditor(); } void onCurrentIndexChanged(int index) { if (index >= 0) { m_property.setValue( itemData(index).value(), m_delegate->editReason()); } } private: QtnPropertyDelegatePenWidth *m_delegate; QtnPropertyPenWidthBase &m_property; unsigned m_updating; class ItemDelegate : public QStyledItemDelegate { QComboBox *m_owner; public: ItemDelegate(QComboBox *owner) : m_owner(owner) { } void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { QStyledItemDelegate::paint(painter, option, index); drawPenWidth(m_owner->style(), index.data(Qt::UserRole).value(), *painter, option.rect); } }; }; bool QtnPropertyDelegatePenWidth::propertyValueToStrImpl( QString &strValue) const { return owner().toStr(strValue); } void QtnPropertyDelegatePenWidth::drawValueImpl( QStylePainter &painter, const QRect &rect) const { drawPenWidth(painter.style(), owner().value(), painter, rect); } QWidget *QtnPropertyDelegatePenWidth::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { auto combo = new QtnPropertyPenWidthComboBox(this, parent); combo->setGeometry(rect); if (inplaceInfo && stateProperty()->isEditableByUser()) combo->showPopup(); return combo; } ================================================ FILE: Demo/PenWidth/PropertyDelegatePenWidth.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_PEN_WIDTH_H #define PROPERTY_DELEGATE_PEN_WIDTH_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" class QtnPropertyPenWidthBase; class QtnPropertyDelegatePenWidth : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegatePenWidth) public: QtnPropertyDelegatePenWidth(QtnPropertyPenWidthBase &owner) : QtnPropertyDelegateTyped(owner) { } protected: bool propertyValueToStrImpl(QString &strValue) const override; void drawValueImpl( QStylePainter &painter, const QRect &rect) const override; QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; }; #endif // PROPERTY_DELEGATE_PEN_WIDTH_H ================================================ FILE: Demo/PenWidth/PropertyPenWidth.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyPenWidth.h" QDataStream &operator<<(QDataStream &stream, const PenWidth penWidth) { stream << (qint64) penWidth; return stream; } QDataStream &operator>>(QDataStream &stream, PenWidth &penWidth) { qint64 data = 0; stream >> data; penWidth = (PenWidth) data; return stream; } bool QtnPropertyPenWidthBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { static QMap str2PenWidth = { { "Default", PenWidth::Default }, { "Thin", PenWidth::Thin }, { "Middle", PenWidth::Middle }, { "Thick", PenWidth::Thick } }; setValue(str2PenWidth.value(str, PenWidth::Default), reason); return true; } bool QtnPropertyPenWidthBase::toStrImpl(QString &str) const { switch (value()) { case PenWidth::Default: str = "Default"; return true; case PenWidth::Thin: str = "Thin"; return true; case PenWidth::Middle: str = "Middle"; return true; case PenWidth::Thick: str = "Thick"; return true; } return false; } ================================================ FILE: Demo/PenWidth/PropertyPenWidth.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_PEN_WIDTH_H #define PROPERTY_PEN_WIDTH_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include enum class PenWidth { Default = 0, Thin = 1, Middle = 2, Thick = 3 }; QDataStream &operator<<(QDataStream &stream, const PenWidth penWidth); QDataStream &operator>>(QDataStream &stream, PenWidth &penWidth); Q_DECLARE_METATYPE(PenWidth) class QtnPropertyPenWidthBase : public QtnSinglePropertyBase { Q_OBJECT QtnPropertyPenWidthBase( const QtnPropertyPenWidthBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyPenWidthBase(QObject *parent) : QtnSinglePropertyBase(parent) { } protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; private: P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyPenWidthBase) }; class QtnPropertyPenWidthCallback : public QtnSinglePropertyCallback { Q_OBJECT QtnPropertyPenWidthCallback( const QtnPropertyPenWidthCallback &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyPenWidthCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyPenWidthCallback, QtnPropertyPenWidthBase) }; class QtnPropertyPenWidth : public QtnSinglePropertyValue { Q_OBJECT QtnPropertyPenWidth(const QtnPropertyPenWidth &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyPenWidth(QObject *parent) : QtnSinglePropertyValue(parent) { } P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyPenWidth, QtnPropertyPenWidthBase) }; #endif // PROPERTY_PEN_WIDTH_H ================================================ FILE: Demo/main.cpp ================================================ #include "MainWindow.h" #include void regABColorDelegates(); void regIntListDelegates(); void regLayerDelegates(); void regPenWidthDelegates(); void regFreqDelegates(); int main(int argc, char *argv[]) { regABColorDelegates(); regIntListDelegates(); regLayerDelegates(); regPenWidthDelegates(); regFreqDelegates(); QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } ================================================ FILE: Demo/mydialog.cpp ================================================ #include "mydialog.h" #include "ui_mydialog.h" MyDialog::MyDialog(QWidget* parent, QtnPropertySet& propertySet, const QtnPropertySet* defaultProperty) : QDialog(parent), ui(new Ui::MyDialog), m_defaultProperty(defaultProperty) { ui->setupUi(this); ui->widget->setPropertySet(&propertySet); } MyDialog::~MyDialog() { delete ui; } ================================================ FILE: Demo/mydialog.h ================================================ #ifndef MYDIALOG_H #define MYDIALOG_H #include #include "QtnProperty/Property.h" namespace Ui { class MyDialog; } class MyDialog : public QDialog { Q_OBJECT public: MyDialog(QWidget *parent, QtnPropertySet &properties, const QtnPropertySet *defaultProperties = nullptr); ~MyDialog(); private: Ui::MyDialog *ui; const QtnPropertySet *m_defaultProperty; }; #endif // MYDIALOG_H ================================================ FILE: Demo/mydialog.ui ================================================ MyDialog 0 0 666 300 Dialog QLayout::SetDefaultConstraint 0 0 Qt::Vertical QDialogButtonBox::Cancel|QDialogButtonBox::Ok false Qt::Vertical QSizePolicy::MinimumExpanding 0 0 QtnPropertyWidgetEx QWidget
QtnProperty/PropertyWidgetEx.h
1
buttonBox accepted() MyDialog accept() 248 254 157 274 buttonBox rejected() MyDialog reject() 316 260 286 274
================================================ FILE: Docs/Doxyfile ================================================ # Doxyfile 1.8.3.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. PROJECT_NAME = QtnProperty # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = . # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. Note that you specify absolute paths here, but also # relative paths, which will be relative from the directory where doxygen is # started. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding # "class=itcl::class" will allow you to use the command class in the # itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, # and language is one of the parsers supported by doxygen: IDL, Java, # Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, # C++. For instance to make doxygen treat .inc files as Fortran files (default # is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note # that for custom extensions you also need to set FILE_PATTERNS otherwise the # files are not read by doxygen. EXTENSION_MAPPING = # If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all # comments according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you # can mix doxygen, HTML, and XML commands with Markdown formatting. # Disable only in case of backward compatibilities issues. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented classes, # or namespaces to their corresponding documentation. Such a link can be # prevented in individual cases by by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES (the # default) will make doxygen replace the get and set methods by a property in # the documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields will be shown inline in the documentation # of the scope in which they are defined (i.e. file, namespace, or group # documentation), provided this scope is documented. If set to NO (the default), # structs, classes, and unions are shown on a separate page (for HTML and Man # pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penalty. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. SYMBOL_CACHE_SIZE = 0 # Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be # set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given # their name and scope. Since this can be an expensive process and often the # same symbol appear multiple times in the code, doxygen keeps a cache of # pre-resolved symbols. If the cache is too small doxygen will become slower. # If the cache is too large, memory is wasted. The cache size is given by this # formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = NO # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if section-label ... \endif # and \cond section-label ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. Do not use # file names with spaces, bibtex cannot handle them. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = .. \ ../../Utils # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.markdown \ *.md \ *.mm \ *.dox \ *.py \ *.f90 \ *.f \ *.for \ *.vhd \ *.vhdl # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = ../Demo \ ../Tests \ ../PEG # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = ./img # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = # If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page (index.html). # This can be useful if you have a project on for instance GitHub and want reuse # the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C, C++ and Fortran comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If left blank doxygen will # generate a default style sheet. Note that it is recommended to use # HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this # tag will in the future become obsolete. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional # user-defined cascading style sheet that is included after the standard # style sheets created by doxygen. Using this option one can overrule # certain style aspects. This is preferred over using HTML_STYLESHEET # since it does not replace the standard style sheet and is therefor more # robust against future updates. Doxygen will copy the style sheet file to # the output directory. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of # entries shown in the various tree structured indices initially; the user # can expand and collapse entries dynamically later on. Doxygen will expand # the tree to such a level that at most the specified number of entries are # visible (unless a fully collapsed tree already exceeds this amount). # So setting the number of entries 1 will produce a full collapsed tree by # default. 0 is a special value representing an infinite number of entries # and will result in a full expanded tree by default. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely # identify the documentation publisher. This should be a reverse domain-name # style string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) # at top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. Since the tabs have the same information as the # navigation tree you can set this option to NO if you already set # GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. # Since the tree basically has the same information as the tab index you # could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you may also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and # SVG. The default value is HTML-CSS, which is slower, but has the best # compatibility. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to # the MathJax Content Delivery Network so you can quickly see the result without # installing MathJax. However, it is strongly recommended to install a local # copy of MathJax from http://www.mathjax.org before deployment. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. MATHJAX_EXTENSIONS = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. # There are two flavours of web server based search depending on the # EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for # searching and an index file used by the script. When EXTERNAL_SEARCH is # enabled the indexing and searching needs to be provided by external tools. # See the manual for details. SERVER_BASED_SEARCH = NO # When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP # script for searching. Instead the search results are written to an XML file # which needs to be processed by an external indexer. Doxygen will invoke an # external search engine pointed to by the SEARCHENGINE_URL option to obtain # the search results. Doxygen ships with an example indexer (doxyindexer) and # search engine (doxysearch.cgi) which are based on the open source search engine # library Xapian. See the manual for configuration details. EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will returned the search results when EXTERNAL_SEARCH is enabled. # Doxygen ships with an example search engine (doxysearch) which is based on # the open source search engine library Xapian. See the manual for configuration # details. SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the # SEARCHDATA_FILE tag the name of this file can be specified. SEARCHDATA_FILE = searchdata.xml # When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the # EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is # useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple # projects and redirect the results back to the right project. EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are # all added to the same external search index. Each project needs to have a # unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id # of to a relative location where the documentation can be found. # The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. For each # tag file the location of the external documentation should be added. The # format of a tag file without this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths # or URLs. Note that each tag file must have a unique name (where the name does # NOT include the path). If a tag file is not located in the directory in which # doxygen is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will use the Helvetica font for all dot files that # doxygen generates. When you want a differently looking font you can specify # the font name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or by setting # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If the UML_LOOK tag is enabled, the fields and methods are shown inside # the class node. If there are many fields or methods and many nodes the # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS # threshold limits the number of items for each type to make the size more # managable. Set this to 0 for no limit. Note that the threshold may be # exceeded by 50% before the limit is enforced. UML_LIMIT_NUM_FIELDS = 10 # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES ================================================ FILE: Docs/Example/TextAttributes.pef ================================================ #include "QtnProperty/PropertyCore.h" #include "QtnProperty/PropertyGUI.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); } } ================================================ FILE: Docs/Example/TextAttributes.peg.cpp ================================================ #include "TextAttributes.peg.h" QtnPropertySetTextAttributes::QtnPropertySetTextAttributes(QObject* parent) : QtnPropertySet(parent) , WordWrap(*qtnCreateProperty(this)) , Height(*qtnCreateProperty(this)) , Color(*qtnCreateProperty(this)) { init(); connectSlots(); connectDelegates(); } QtnPropertySetTextAttributes::~QtnPropertySetTextAttributes() { disconnectSlots(); } QtnPropertySetTextAttributes& QtnPropertySetTextAttributes::operator=(const QtnPropertySetTextAttributes& other) { Q_UNUSED(other); WordWrap = other.WordWrap; Height = other.Height; Color = other.Color; return *this; } QtnPropertySet* QtnPropertySetTextAttributes::createNewImpl(QObject* parentForNew) const { return new QtnPropertySetTextAttributes(parentForNew); } QtnPropertySet* QtnPropertySetTextAttributes::createCopyImpl(QObject* parentForCopy) const { QtnPropertySetTextAttributes* p = new QtnPropertySetTextAttributes(parentForCopy); *p = *this; return p; } bool QtnPropertySetTextAttributes::copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) { Q_UNUSED(ignoreMask); auto theCopyFrom = qobject_cast(propertySetCopyFrom); if (!theCopyFrom) return false; if (!(theCopyFrom->WordWrap.state() & ignoreMask)) { WordWrap = theCopyFrom->WordWrap; } if (!(theCopyFrom->Height.state() & ignoreMask)) { Height = theCopyFrom->Height; } if (!(theCopyFrom->Color.state() & ignoreMask)) { Color = theCopyFrom->Color; } return true; } void QtnPropertySetTextAttributes::init() { static QString TextAttributes_name = QStringLiteral("TextAttributes"); setName(TextAttributes_name); // start children initialization static QString WordWrap_name = QStringLiteral("WordWrap"); WordWrap.setName(WordWrap_name); static QString WordWrap_description = "Text word wrapping"; WordWrap.setDescription(WordWrap_description); WordWrap.setValue(true); static QString Height_name = QStringLiteral("Height"); Height.setName(Height_name); static QString Height_description = "Text height"; Height.setDescription(Height_description); Height.setMaxValue(100); Height.setMinValue(1); Height.setStepValue(1); Height.setValue(16); static QString Color_name = QStringLiteral("Color"); Color.setName(Color_name); static QString Color_description = "Foreground text color"; Color.setDescription(Color_description); Color.setValue(QColor(0, 0, 0)); // end children initialization } void QtnPropertySetTextAttributes::connectSlots() { } void QtnPropertySetTextAttributes::disconnectSlots() { } void QtnPropertySetTextAttributes::connectDelegates() { } ================================================ FILE: Docs/Example/TextAttributes.peg.h ================================================ #ifndef TEXTATTRIBUTES_H #define TEXTATTRIBUTES_H #include "QtnProperty/PropertyCore.h" #include "QtnProperty/PropertyGUI.h" class QtnPropertySetTextAttributes: public QtnPropertySet { Q_OBJECT //Q_DISABLE_COPY(QtnPropertySetTextAttributes) public: // constructor declaration explicit QtnPropertySetTextAttributes(QObject* parent = nullptr); // destructor declaration virtual ~QtnPropertySetTextAttributes() override; // assignment declaration QtnPropertySetTextAttributes& operator=(const QtnPropertySetTextAttributes& other); // start children declarations QtnPropertyBool& WordWrap; QtnPropertyInt& Height; QtnPropertyQColor& Color; // end children declarations protected: // cloning implementation QtnPropertySet* createNewImpl(QObject* parentForNew) const override; QtnPropertySet* createCopyImpl(QObject* parentForCopy) const override; // copy values implementation bool copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) override; private: void init(); void connectSlots(); void disconnectSlots(); void connectDelegates(); }; #endif // TEXTATTRIBUTES_H ================================================ FILE: Internal/BaseConfig.pri ================================================ QTNPROPERTY_BIN_PREFIX = $$PWD/.. QTNPROPERTY_BIN = $$QTNPROPERTY_BIN_PREFIX/bin win32 { QTNPROPERTY_BIN = $$QTNPROPERTY_BIN-win32 msvc:QTNPROPERTY_BIN = $$QTNPROPERTY_BIN-msvc$$QMAKE_MSC_VER } emscripten:QTNPROPERTY_BIN = $$QTNPROPERTY_BIN-emscripten else:macx:QTNPROPERTY_BIN = $$QTNPROPERTY_BIN-osx else:linux:QTNPROPERTY_BIN = $$QTNPROPERTY_BIN-linux isEmpty(QTNPROPERTY_BIN) { message("Only mac/win32/linux/emscripten supported") QTNPROPERTY_BIN = "FAIL" } else { clang:QTNPROPERTY_BIN = $$QTNPROPERTY_BIN-clang else:gcc:QTNPROPERTY_BIN = $$QTNPROPERTY_BIN-gcc QTNPROPERTY_BIN = $$QTNPROPERTY_BIN-$$QT_ARCH CONFIG(debug, debug|release) { QTNPROPERTY_BIN = $$QTNPROPERTY_BIN/debug } } ================================================ FILE: Internal/TargetConfig.pri ================================================ isEmpty(QTNPROPERTY_BIN) { include($$PWD/BaseConfig.pri) } DESTDIR = $$QTNPROPERTY_BIN CONFIG += c++11 msvc { DEFINES += _CRT_SECURE_NO_WARNINGS } clang:QMAKE_CXXFLAGS_WARN_ON += \ -Wno-deprecated-copy \ -Wno-unknown-warning-option \ -Wno-deprecated-declarations macx:DYNAMIC_LIBS.path = "Contents/MacOS" CONFIG(debug, debug|release) { DEFINES += DEBUG } else { DEFINES += NDEBUG } ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: NOTICE ================================================ Apache QtnProperty Copyright 2012-2020 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). ================================================ FILE: PEG/Bison.pri ================================================ bison.name = Bison ${QMAKE_FILE_IN} bison.input = BISON_SOURCES bison.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.parser.cpp win32:bison.commands = win_bison -d -o ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.parser.cpp ${QMAKE_FILE_IN} unix::bison.commands = bison -d -o ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.parser.cpp ${QMAKE_FILE_IN} #-Wmidrule-value -t bison.CONFIG += targets_predeps bison.variable_out = GENERATED_SOURCES silent:bison.commands = @echo Bison ${QMAKE_FILE_IN} && $$bison.commands QMAKE_EXTRA_COMPILERS += bison ================================================ FILE: PEG/Flex.pri ================================================ flex.name = Flex ${QMAKE_FILE_IN} flex.input = FLEX_SOURCES flex.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.lexer.cpp win32:flex.commands = win_flex --wincompat -o ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.lexer.cpp ${QMAKE_FILE_IN} unix:flex.commands = flex -o ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.lexer.cpp ${QMAKE_FILE_IN} flex.CONFIG += target_predeps flex.variable_out = GENERATED_SOURCES silent:flex.commands = @echo Lex ${QMAKE_FILE_IN} && $$flex.commands QMAKE_EXTRA_COMPILERS += flex ================================================ FILE: PEG/PEG.pri ================================================ # To use *.pef files in your project you should: # 1. Include this PEG.pri file to your project file # 2. List your *.pef files in PEG_SOURCES variable # 3. Define PEG_TOOL to point to QtnPEG before including # PEG.pri file in your pro file isEmpty(QTNPROPERTY_BIN) { include($$PWD/../Internal/BaseConfig.pri) } isEmpty(PEG_TOOL) { win32:PEG_TOOL = $$QTNPROPERTY_BIN/QtnPEG.exe else:PEG_TOOL = $$QTNPROPERTY_BIN/QtnPEG } peg.name = PropertyEnum generator ${QMAKE_FILE_IN} peg.input = PEG_SOURCES peg.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.peg.cpp peg.commands = $$PEG_TOOL ${QMAKE_FILE_IN} peg.CONFIG += target_predeps peg.variable_out = SOURCES silent:peg.commands = @echo PEG ${QMAKE_FILE_IN} && $$peg.commands QMAKE_EXTRA_COMPILERS += peg peg_header.name = PEG Headers ${QMAKE_FILE_IN} peg_header.input = PEG_SOURCES peg_header.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.peg.h peg_header.commands = $$escape_expand(\\n) # empty command peg_header.CONFIG += target_predeps no_link peg_header.variable_out = PEG_MOC_HEADERS QMAKE_EXTRA_COMPILERS += peg_header load(moc) peg_moc.name = my_moc_header peg_moc.output = $$moc_header.output peg_moc.input = PEG_MOC_HEADERS peg_moc.commands = $$moc_header.commands peg_moc.variable_out = GENERATED_SOURCES QMAKE_EXTRA_COMPILERS += peg_moc ================================================ FILE: PEG/PEG.pro ================================================ include(../Internal/TargetConfig.pri) include(Bison.pri) include(Flex.pri) QT += core QT -= gui clang:QMAKE_CXXFLAGS_WARN_ON += \ -Wno-deprecated-register \ -Wno-unneeded-internal-declaration \ -Wno-unused-const-variable gcc:QMAKE_CXXFLAGS_WARN_ON += \ -Wno-unused-function TARGET = QtnPEG CONFIG += cmdline CONFIG -= app_bundle TEMPLATE = app VERSION = 2.0.0 SOURCES += main.cpp \ PropertyEnumGenerator.cpp BISON_SOURCES += PropertyEnum.y FLEX_SOURCES += PropertyEnum.l OTHER_FILES += \ PropertyEnum.l \ PropertyEnum.y HEADERS += \ PropertyEnumGeneratorCommon.h \ PropertyEnumGenerator.h msvc:QMAKE_CXXFLAGS += /wd4065 /wd4267 /wd4005 ================================================ FILE: PEG/PropertyEnum.l ================================================ %option 8bit %option warn %option yylineno %option noyywrap %option stack %option bison-bridge bison-locations %x ASSIGN_STATE %x LINE_COMMENT_STATE %x CPP_COMMENT_STATE %x CPP_STRING_STATE %x CPP_CHAR_STATE %x INCLUDE_STATE %x CPP_CODE_STATE %x CPP_CODE_STATE2 %x STRING_STATE %x INITIALIZATION_LIST_STATE %{ #include "PropertyEnumGeneratorCommon.h" #include "PropertyEnum.parser.hpp" int yycolumn = 1; int yy_bracket_count = 0; extern void yyerror(/*YYLTYPE *yylloc,*/ char const *s); #define YY_USER_ACTION yylloc->first_line = yylloc->last_line = yylineno; \ yylloc->first_column = yycolumn; yylloc->last_column = yycolumn + yyleng - 1; \ yycolumn += yyleng; %} %% [ \t]+ /* skip whitespaces */ [\r\n] { yycolumn = 1; } #include|#include_h { yy_push_state(INCLUDE_STATE); return INCLUDE_H; } #include_cpp { yy_push_state(INCLUDE_STATE); return INCLUDE_CPP; } code_h { return CODE_H; } code_cpp { return CODE_CPP; } property_set { return PROPERTY_SET; } property { return PROPERTY; } extern { return EXTERN; } slot { return SLOT; } delegate { return DELEGATE; } enum { return ENUM; } public|protected|private { *yylval = yytext; return ACCESS_ID; } [[:alpha:]_]+[[:alnum:]_]* { *yylval = yytext; return ID; } "{" { return CPP_BRACKET_OPEN; } "}" { return CPP_BRACKET_CLOSE; } "(" { return '('; } ")" { return ')'; } ";" { return SEMICOLON; } ":" { return COLON; } "::" { return DBL_COLON; } "," { return COMMA; } "." { return DOT; } "~" { return TILDE; } "=" { yy_push_state(ASSIGN_STATE); return ASSIGN; } [+-]?[[:digit:]]+ { *yylval = yytext; return NUMBER; } [LR]?\" { yymore(); yy_push_state(STRING_STATE); yy_push_state(CPP_STRING_STATE); } . { printf( "Unrecognized character: %s\n", yytext ); yyerror("scan error"); exit(1); } { . { yy_pop_state(); char lastChar = yytext[yyleng-1]; yytext[yyleng-1] = '\0'; *yylval = yytext; unput(lastChar); return STR; } } { [^\n]* { yy_pop_state(); *yylval = yytext; return INCLUDE_NAME; } } { "/*" { yy_push_state(CPP_COMMENT_STATE); } "}" { printf( "Unbalanced } bracket\n"); yyerror("scan error"); exit(1); } "{" { yymore(); yy_push_state(CPP_CODE_STATE2); yy_bracket_count = 1; } [^\";{}]+ { yymore(); } [LR]?\" { yymore(); yy_push_state(CPP_STRING_STATE); } ; { yy_pop_state(); // skip ';' char yytext[yyleng-1] = '\0'; *yylval = yytext; *yylval = yylval->trimmed(); return VALUE_TO_ASSIGN; } } { [^\\\"]+ { yymore(); } "\\\"" { yymore(); } "\\"[^\"] { yymore(); } "\""[ \t]*"\"" { yymore(); } "\""[\r\n]*"\"" { yycolumn = 1; yymore(); } \" { yymore(); yy_pop_state(); } } "//" { yy_push_state(LINE_COMMENT_STATE); } { [^\r\n]* { /* skip line comment */ yy_pop_state(); } } "/*" { yy_push_state(CPP_COMMENT_STATE); } { [^*]* { /* skip cpp comment */ } "*"+[^/] { /* skip cpp comment */ } "*"+"/" { yy_pop_state(); } } { [^{}]* { yymore(); } "{" { yymore(); ++yy_bracket_count; } "}" { --yy_bracket_count; if (yy_bracket_count == 0) { yy_pop_state(); // skip close bracked yytext[yyleng-1] = '\0'; *yylval = yytext; return CPP_CODE; } else { yymore(); } } } { [^{}]* { yymore(); } "{" { yymore(); ++yy_bracket_count; } "}" { yymore(); --yy_bracket_count; if (yy_bracket_count == 0) yy_pop_state(); } } { [^{]* { yymore(); } "{" { yy_pop_state(); // skip open bracked yytext[yyleng-1] = '\0'; *yylval = yytext; unput('{'); return INITIALIZATION_LIST; } } %% void yy_push_state_cpp_code() { yy_push_state(CPP_CODE_STATE); yy_bracket_count = 1; } void yy_push_state_initialization_list() { yy_push_state(INITIALIZATION_LIST_STATE); yy_bracket_count = 1; } ================================================ FILE: PEG/PropertyEnum.y ================================================ %{ #include "PropertyEnumGeneratorCommon.h" #include "PropertyEnumGenerator.h" #include void yyerror(/*YYLTYPE *yylloc, */char const *); #define YYLEX_PARAM &yylval, &yylloc #define YYPRINT(File, Type, Value) fprintf ((File), "%s", (Value).toLatin1().data()) extern void yy_push_state_cpp_code(); extern void yy_push_state_initialization_list(); %} %locations //%define parse.error verbose //%define api.pure full %lex-param {YYLEX_PARAM} %token PROPERTY_SET PROPERTY INCLUDE_H INCLUDE_CPP INCLUDE_NAME EXTERN ID CPP_BRACKET_OPEN CPP_BRACKET_CLOSE ASSIGN SEMICOLON COLON DBL_COLON COMMA DOT TILDE VALUE_TO_ASSIGN ACCESS_ID SLOT DELEGATE CODE_H CODE_CPP CPP_CODE ENUM NUMBER STR INITIALIZATION_LIST %% pef_body: /* empty */ | pef_body include_h | pef_body include_cpp | pef_body source_code | pef_body property_set | pef_body enum ; include_h: INCLUDE_H INCLUDE_NAME { peg.code.append(QSharedPointer(new IncludeCode($2, true))); } ; include_cpp: INCLUDE_CPP INCLUDE_NAME { peg.code.append(QSharedPointer(new IncludeCode($2, false))); } ; source_code: CODE_H CPP_BRACKET_OPEN { yy_push_state_cpp_code(); } CPP_CODE { QSharedPointer code(new SourceCode($4, true)); if (pegContext.currPropertySet) pegContext.currPropertySet->sourceCodes.append(code); else peg.code.append(code); } | CODE_CPP CPP_BRACKET_OPEN { yy_push_state_cpp_code(); } CPP_CODE { QSharedPointer code(new SourceCode($4, false)); if (pegContext.currPropertySet) pegContext.currPropertySet->sourceCodes.append(code); else peg.code.append(code); } ; property_set: property_set_head property_set_body { pegContext.commitPropertySet(); } ; property_set_head: PROPERTY_SET ID { pegContext.startPropertySet(); pegContext.currPropertySet->setName($2); } ; type_decl: ID { pegContext.currType.namespaceName = ""; pegContext.currType.name = $1; } | namespace_name DBL_COLON ID { pegContext.currType.namespaceName = $1; pegContext.currType.name = $3; } ; namespace_name: ID | namespace_name DBL_COLON ID ; optional_semicolon: /* empty */ | SEMICOLON ; property_set_body: CPP_BRACKET_OPEN property_set_declarations CPP_BRACKET_CLOSE optional_semicolon { } ; property_set_declarations: /* empty */ | property_set_declarations property_declaration | property_set_declarations value_declaration | property_set_declarations slot_declaration | property_set_declarations sub_property_set | property_set_declarations source_code | property_set_declarations delegate_declaration | property_set_declarations constructor | property_set_declarations destructor ; sub_property_set: property_set | property_set_with_id | property_set_extern ; property_set_with_id: property_set_head ID property_set_body { pegContext.currPropertySet->name = $2; pegContext.commitPropertySet(); // add sub property set as member pegContext.currPropertySet->members.push_back(pegContext.currPropertySet->subPropertySets.last()); } ; property_set_extern: property_set_extern_head property_set_extern_tail ; property_set_extern_head: EXTERN PROPERTY_SET type_decl ID { pegContext.startPropertySet(); pegContext.currPropertySet->_extern = true; pegContext.currPropertySet->selfType = pegContext.currentPropertySetType(); pegContext.currPropertySet->name = $4; } ; property_set_extern_tail: sub_item_body { pegContext.commitPropertySet(); // add sub property set as member pegContext.currPropertySet->members.push_back(pegContext.currPropertySet->subPropertySets.last()); } | SEMICOLON { pegContext.commitPropertySet(); // add sub property set as member pegContext.currPropertySet->members.push_back(pegContext.currPropertySet->subPropertySets.last()); } ; property_declaration: property_declaration_head property_declaration_tail ; property_declaration_head: type_decl ID { pegContext.startProperty(); pegContext.currProperty->selfType = pegContext.currentPropertyType(); pegContext.currProperty->name = $2; } ; property_declaration_tail: sub_item_body { pegContext.commitProperty(); } | SEMICOLON { pegContext.commitProperty(); } ; sub_item_body: CPP_BRACKET_OPEN sub_item_declarations CPP_BRACKET_CLOSE { } ; sub_item_declarations: /* empty */ | sub_item_declarations value_declaration | sub_item_declarations slot_declaration | sub_item_declarations delegate_declaration ; value_declaration: name_to_assign ASSIGN VALUE_TO_ASSIGN { AssignInfo info; info.member = pegContext.currAssignMember; info.value = $3; pegContext.current()->assignments.insert(pegContext.currAssignFunc, info); } ; name_to_assign: ID { pegContext.currAssignFunc = $1; pegContext.currAssignMember = ""; } | name_to_assign DOT ID { pegContext.currAssignFunc = $3; pegContext.currAssignMember = $1; } ; slot_declaration: SLOT name_to_assign { if (!pegContext.checkSlotName(pegContext.currAssignFunc)) { QString error = QString("Unrecognized slot name <%1>.").arg(pegContext.currAssignFunc); yyerror(error.toLatin1().data()); exit(1); } } CPP_BRACKET_OPEN { yy_push_state_cpp_code(); } CPP_CODE { AssignInfo info; info.member = pegContext.currAssignMember; info.value = $6; pegContext.current()->slots_code.insert(pegContext.currAssignFunc, info); } ; delegate_declaration: DELEGATE { if (pegContext.current()->delegateInfo.data()) { QString error = QString("Delegate for object <%1> already defined.").arg(pegContext.current()->name); yyerror(error.toLatin1().data()); exit(1); } pegContext.current()->delegateInfo.reset(new DelegateInfo()); } delegate_tail ; delegate_tail: ID delegate_body { pegContext.current()->delegateInfo->name = $1; } | delegate_body ; delegate_body: SEMICOLON | CPP_BRACKET_OPEN delegate_attributes CPP_BRACKET_CLOSE ; delegate_attributes: /*empty*/ | delegate_attributes delegate_attribute ; delegate_attribute: ID ASSIGN VALUE_TO_ASSIGN { pegContext.current()->delegateInfo->attributes[$1] = $3; } constructor: ID '(' ')' initialization_list CPP_BRACKET_OPEN { yy_push_state_cpp_code(); } CPP_CODE { pegContext.currPropertySet->setConstructorCode($1, $4, $7); } ; initialization_list: /*empty*/ | COLON { yy_push_state_initialization_list(); } INITIALIZATION_LIST { $$ = $3; } ; destructor: TILDE ID '(' ')' CPP_BRACKET_OPEN { yy_push_state_cpp_code(); } CPP_CODE { pegContext.currPropertySet->setDestructorCode($2, $7); } ; enum: ENUM ID { pegContext.enumCode.reset(new EnumCode($2)); } CPP_BRACKET_OPEN enum_values_list CPP_BRACKET_CLOSE optional_semicolon { peg.code.append(pegContext.enumCode); pegContext.enumCode.reset(); } ; enum_values_list: /* none */ | enum_values_list2 ; enum_values_list2: enum_value | enum_values_list2 COMMA enum_value ; enum_value: ID '(' NUMBER COMMA STR ')' { EnumCode::EnumItemCode item; item.name = $1; bool success = false; item.id = $3.toInt(&success); if (!success) { QString error = QString("Unrecognized enum item id <%1>.").arg($3); yyerror(error.toLatin1().data()); exit(1); } item.text = $5; pegContext.enumCode->items.append(item); } enum_states_list ; enum_states_list: /* none */ | enum_states_list ID { pegContext.enumCode->items.last().states.append($2); } ; %% void yyerror(/*YYLTYPE *yylloc, */char const *s) { fprintf(stderr, "Parser error: (%d,%d)-(%d,%d) '%s'\n" ,yylloc.first_line ,yylloc.first_column ,yylloc.last_line ,yylloc.last_column ,s); } ================================================ FILE: PEG/PropertyEnumGenerator.cpp ================================================ /* Copyright (c) 2012-2016 Alex Zhondin Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include "PropertyEnumGenerator.h" #include #include #include #include PEG &peg = PEG::instance(); // special values that initialized in constructor static Exceptions createSetExceptions() { Exceptions exceptions; exceptions.insert("parent"); return exceptions; } static Exceptions setExceptions = createSetExceptions(); static Signatures createSlotSignatures() { Signatures _slots; _slots.insert("propertyWillChange", { "QtnPropertyChangeReason reason, " "QtnPropertyValuePtr newValue, " "int typeId", "Q_UNUSED(reason); " "Q_UNUSED(newValue);" "Q_UNUSED(typeId);" }); _slots.insert("propertyDidChange", { "QtnPropertyChangeReason reason", "Q_UNUSED(reason);" }); _slots.insert("propertyValueAccept", { "QtnPropertyValuePtr valueToAccept, " "bool* accept", "Q_UNUSED(valueToAccept); " "Q_UNUSED(accept);" }); return _slots; } static Signatures slotsSignatures = createSlotSignatures(); static QString slotSignature(const QString &name) { auto it = slotsSignatures.find(name); if (it == slotsSignatures.end()) peg.fatalError("Cannot recognize slot " + name); return it.value().arguments; } static QString slotUnusedCode(const QString &name) { auto it = slotsSignatures.find(name); if (it == slotsSignatures.end()) peg.fatalError("Cannot recognize slot " + name); return it.value().unusedCode; } static QString valueByName(const Assignments &assignments, const QString &name, const QString &defaultValue) { auto it = assignments.find(name); if (it == assignments.end()) return defaultValue; if (!it->member.isEmpty()) return defaultValue; return it->value; } static QString capitalize(QString text) { return text.left(1).toUpper() + text.mid(1); } static void assignmentSetCode( QString prefix, Assignments::ConstIterator assignment, TextStreamIndent &s) { QString name; if (!prefix.isEmpty()) name += prefix + "."; if (!assignment.value().member.isEmpty()) name += assignment.value().member + "."; if (assignment.key() != "description") { s.newLine() << QString("%1set%2(%3);") .arg(name, capitalize(assignment.key()), assignment.value().value); } else { QString var = name + assignment.key(); var.replace(".", "_"); s.newLine() << QString("static QString %1 = %2;") .arg(var, assignment.value().value); s.newLine() << QString("%1set%2(%3);") .arg(name, capitalize(assignment.key()), var); } } static void assignmentsSetCode(QString prefix, const Assignments &assignments, const Exceptions &exceptions, TextStreamIndent &s) { for (auto it = assignments.cbegin(); it != assignments.cend(); ++it) { if (!exceptions.contains(it.key())) assignmentSetCode(prefix, it, s); } } static QString slotName( const QString &name, const QString *member1, const QString *member2) { QString slotName = "on_"; if (member1 && !member1->isEmpty()) { QString s = *member1; slotName += s.replace(QChar('.'), QChar('_')) + "_"; } if (member2 && !member2->isEmpty()) { QString s = *member2; slotName += s.replace(QChar('.'), QChar('_')) + "_"; } return slotName + name; } void DelegateInfo::generateCode(TextStreamIndent &s) const { s.newLine() << QString("QtnPropertyDelegateInfo info;"); if (!name.isEmpty()) s.newLine() << QString("info.name = \"%1\";").arg(name); for (auto it = attributes.begin(); it != attributes.end(); ++it) { s.newLine() << QString("info.attributes[\"%1\"] = %2;") .arg(it.key(), it.value()); } s.newLine() << "return info;"; } IncludeCode::IncludeCode(QString name, bool isHeader) : name(name.trimmed()) , isHeader(isHeader) { } void IncludeCode::generateHFile(TextStreamIndent &s) const { if (!isHeader) return; generate(s); } void IncludeCode::generateCppFile(TextStreamIndent &s) const { if (isHeader) return; generate(s); } SourceCode::SourceCode(const QString &code, bool code_h) : code(code) , code_h(code_h) { } void SourceCode::generateHFile(TextStreamIndent &s) const { if (!code_h) return; s.newLine() << code; } void SourceCode::generateCppFile(TextStreamIndent &s) const { if (code_h) return; s.newLine() << code; } PropertySetCode::PropertySetCode() {} void PropertySetCode::setName(QString _name) { name = _name; selfType = "QtnPropertySet" + name; } void PropertySetCode::setSuperType(const PropertySetCode *parent) { if (parent->superType.isEmpty()) superType = parent->selfType; else superType = parent->superType + "::" + parent->selfType; } void PropertySetCode::setConstructorCode( QString _name, QString _initialization_list, QString _code) { if (_name != name) peg.fatalError( QString("Cannot recognize as constructor '%1'.").arg(_name)); if (constructor) peg.fatalError( QString("Constructor for '%1' already defined.").arg(_name)); constructor.reset(new Constructor()); constructor->initialization_list = _initialization_list.trimmed(); constructor->code = _code; } void PropertySetCode::setDestructorCode(QString _name, QString _code) { if (_name != name) peg.fatalError( QString("Cannot recognize as destructor '%1'.").arg(_name)); if (destructor) peg.fatalError( QString("Destructor for '%1' already defined.").arg(_name)); destructor.reset(new Destructor()); destructor->code = _code; } void PropertySetCode::generateHFile(TextStreamIndent &s) const { generateSubPropertySetsDeclarations(s); s << endl; s.newLine() << QString("class %1: public QtnPropertySet").arg(selfType); s.newLine() << "{"; s.addIndent(); s.newLine() << "Q_OBJECT"; s.newLine() << QString("//Q_DISABLE_COPY(%1)").arg(selfType); s << endl; s.newLine(-1) << "public:"; s.newLine() << "// constructor declaration"; s.newLine() << QString("explicit %1(QObject* parent = %2);") .arg(selfType, valueByName(assignments, "parent", "nullptr")); s.newLine() << "// destructor declaration"; s.newLine() << QString("virtual ~%1() override;").arg(selfType); s.newLine() << "// assignment declaration"; s.newLine() << QString("%1& operator=(const %1& other);").arg(selfType); generateChildrenDeclaration(s); s << endl; s.newLine(-1) << "protected:"; s.newLine() << "// cloning implementation"; s.newLine() << QString( "QtnPropertySet* createNewImpl(QObject* parentForNew) const override;"); s.newLine() << QString("QtnPropertySet* createCopyImpl(QObject* " "parentForCopy) const override;"); s.newLine() << "// copy values implementation"; s.newLine() << QString("bool copyValuesImpl(QtnPropertySet* " "propertySetCopyFrom, QtnPropertyState ignoreMask) " "override;"); s << endl; s.newLine(-1) << "private:"; s.newLine() << "void init();"; s.newLine() << "void connectSlots();"; s.newLine() << "void disconnectSlots();"; s.newLine() << "void connectDelegates();"; generateSlotsDeclaration(s); s.delIndent(); generateHSourceCode(s); s.newLine() << "};"; } void PropertySetCode::generateCppFile(TextStreamIndent &s) const { generateSubPropertySetsImplementations(s); // constructor implementation s << endl; s.newLine() << QString("%1::%1(QObject* parent)").arg(selfType); s.addIndent(); s.newLine() << QString(": QtnPropertySet(parent)"); generateChildrenInitialization(s); generateConstructorInitializationList(s); s.delIndent(); s.newLine() << "{"; s.addIndent(); if (constructor) s.newLine() << constructor->code; s.newLine() << "init();"; s.newLine() << "connectSlots();"; s.newLine() << "connectDelegates();"; s.delIndent(); s.newLine() << "}"; // destructor implementation s << endl; s.newLine() << selfType << "::~" << selfType << "()"; s.newLine() << "{"; s.addIndent(); if (destructor) s.newLine() << destructor->code; s.newLine() << "disconnectSlots();"; s.delIndent(); s.newLine() << "}"; // assignment implementation s << endl; s.newLine() << QString("%1& %1::operator=(const %1& other)").arg(selfType); s.newLine() << "{"; s.addIndent(); s.newLine() << "Q_UNUSED(other);" << endl; generateChildrenCopy(s); s << endl; s.newLine() << "return *this;"; s.delIndent(); s.newLine() << "}"; // cloning implementation s << endl; s.newLine() << QString( "QtnPropertySet* %1::createNewImpl(QObject* parentForNew) const") .arg(selfType); s.newLine() << "{"; s.addIndent(); s.newLine() << QString("return new %1(parentForNew);").arg(selfType); s.delIndent(); s.newLine() << "}"; s << endl; s.newLine() << QString( "QtnPropertySet* %1::createCopyImpl(QObject* parentForCopy) const") .arg(selfType); s.newLine() << "{"; s.addIndent(); s.newLine() << QString("%1* p = new %1(parentForCopy);").arg(selfType); s.newLine() << "*p = *this;"; s.newLine() << "return p;"; s.delIndent(); s.newLine() << "}"; // copy values implementation s << endl; s.newLine() << QString("bool %1::copyValuesImpl(QtnPropertySet* " "propertySetCopyFrom, QtnPropertyState ignoreMask)") .arg(selfType); s.newLine() << "{"; s.addIndent(); s.newLine() << "Q_UNUSED(ignoreMask);" << endl; generateCopyValues(s); s.delIndent(); s.newLine() << "}"; // initialization s << endl; s.newLine() << "void " << selfType << "::init()"; s.newLine() << "{"; s.addIndent(); s.newLine() << QString("static QString %1_name = QStringLiteral(\"%1\");") .arg(name); s.newLine() << QString("setName(%1_name);").arg(name); assignmentsSetCode("", assignments, setExceptions, s); generateChildrenAssignment(s); s.delIndent(); s.newLine() << "}"; // slots connect/disconnect s << endl; s.newLine() << QString("void %1::connectSlots()").arg(selfType); s.newLine() << "{"; s.addIndent(); generateSlotsConnections(s, "connect"); s.delIndent(); s.newLine() << "}"; s << endl; s.newLine() << QString("void %1::disconnectSlots()").arg(selfType); s.newLine() << "{"; s.addIndent(); generateSlotsConnections(s, "disconnect"); s.delIndent(); s.newLine() << "}"; generateSlotsImplementation(s); // delegates connects s << endl; s.newLine() << QString("void %1::connectDelegates()").arg(selfType); s.newLine() << "{"; s.addIndent(); generateDelegatesConnection(s); s.delIndent(); s.newLine() << "}"; // custom code generateCppSourceCode(s); } void PropertySetCode::generateChildrenDeclaration(TextStreamIndent &s) const { if (members.isEmpty()) return; s.pushWrapperLines( "// start children declarations", "// end children declarations"); foreach (auto p, members) { s.newLine() << p->selfType << "& " << p->name << ";"; } s.popWrapperLines(); } void PropertySetCode::generateChildrenInitialization(TextStreamIndent &s) const { if (members.isEmpty()) return; for (auto it = members.cbegin(); it != members.cend(); ++it) { const PropertySetMemberCode &p = **it; s.newLine() << ", " << p.name << "(*qtnCreateProperty<" << p.selfType << ">(this))"; } } void PropertySetCode::generateChildrenAssignment(TextStreamIndent &s) const { if (members.isEmpty()) return; s.pushWrapperLines( "// start children initialization", "// end children initialization"); foreach (auto p, members) { s.newLine() << QString( "static QString %1_name = QStringLiteral(\"%1\");") .arg(p->name); s.newLine() << QString("%1.setName(%1_name);").arg(p->name); assignmentsSetCode(p->name, p->assignments, setExceptions, s); } s.popWrapperLines(); } void PropertySetCode::generateChildrenCopy(TextStreamIndent &s) const { foreach (auto p, members) { s.newLine() << QString("%1 = other.%1;").arg(p->name); } } void PropertySetCode::generateSubPropertySetsDeclarations( TextStreamIndent &s) const { QVector _subPropertySets = getSubpropertySets(); if (_subPropertySets.isEmpty()) return; for (auto it = _subPropertySets.begin(); it != _subPropertySets.end(); ++it) { (*it)->generateHFile(s); } } void PropertySetCode::generateSubPropertySetsImplementations( TextStreamIndent &s) const { QVector _subPropertySets = getSubpropertySets(); if (_subPropertySets.isEmpty()) return; for (auto it = _subPropertySets.begin(); it != _subPropertySets.end(); ++it) { (*it)->generateCppFile(s); } } void PropertySetCode::generateSlotsDeclaration(TextStreamIndent &s) const { s.pushWrapperLines( "// start slot declarations", "// end slot declarations"); for (auto it = slots_code.begin(); it != slots_code.end(); ++it) { s.newLine() << QString("void %1(%2);") .arg(slotName(it.key(), &it.value().member, nullptr), slotSignature(it.key())); } for (auto it = members.begin(); it != members.end(); ++it) { if (!(*it)->_extern) continue; for (auto jt = (*it)->slots_code.begin(); jt != (*it)->slots_code.end(); ++jt) { s.newLine() << QString("void %1(%2);") .arg(slotName(jt.key(), &(*it)->name, &jt.value().member), slotSignature(jt.key())); } } s.popWrapperLines(); } void PropertySetCode::generateSlotsImplementation(TextStreamIndent &s) const { for (auto it = slots_code.begin(); it != slots_code.end(); ++it) { s << endl; s.newLine() << QString("void %1::%2(%3)") .arg(selfType, slotName(it.key(), &it.value().member, nullptr), slotSignature(it.key())); s.newLine() << "{"; s.addIndent(); s.newLine() << slotUnusedCode(it.key()); s.newLine() << it.value().value; s.delIndent(); s.newLine() << "}"; } for (auto it = members.begin(); it != members.end(); ++it) { if (!(*it)->_extern) continue; for (auto jt = (*it)->slots_code.begin(); jt != (*it)->slots_code.end(); ++jt) { s << endl; s.newLine() << QString("void %1::%2(%3)") .arg(selfType, slotName(jt.key(), &(*it)->name, &jt.value().member), slotSignature(jt.key())); s.newLine() << "{"; s.addIndent(); s.newLine() << slotUnusedCode(jt.key()); s.newLine() << jt.value().value; s.delIndent(); s.newLine() << "}"; } } } void PropertySetCode::generateHSourceCode(TextStreamIndent &s) const { for (auto it = sourceCodes.begin(); it != sourceCodes.end(); ++it) { if (!(*it)->code_h) continue; (*it)->generateHFile(s); } } void PropertySetCode::generateCppSourceCode(TextStreamIndent &s) const { for (auto it = sourceCodes.begin(); it != sourceCodes.end(); ++it) { if ((*it)->code_h) continue; (*it)->generateCppFile(s); } } void PropertySetCode::generateDelegatesConnection(TextStreamIndent &s) const { if (!delegateInfo.isNull()) { s.newLine() << QString( "setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo {"); s.addIndent(); delegateInfo->generateCode(s); s.delIndent(); s.newLine() << "});"; } foreach (auto p, members) { if (!p->delegateInfo.isNull()) { s.newLine() << QString( "%1.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo {") .arg(p->name); s.addIndent(); p->delegateInfo->generateCode(s); s.delIndent(); s.newLine() << "});"; } } } void PropertySetCode::generateConstructorInitializationList( TextStreamIndent &s) const { if (!constructor || constructor->initialization_list.isEmpty()) return; s.newLine() << ", " << constructor->initialization_list; } void PropertySetCode::generateCopyValues(TextStreamIndent &s) const { s.newLine() << QString( "auto theCopyFrom = qobject_cast<%1*>(propertySetCopyFrom);") .arg(selfType); s.newLine() << "if (!theCopyFrom)"; s.newLine(1) << "return false;"; s << endl; Q_ASSERT(members.size() >= subPropertySets.size()); auto mIt = members.begin(); auto sIt = subPropertySets.begin(); auto sEnd = subPropertySets.end(); for (auto mEnd = members.end(); mIt != mEnd; ++mIt) { if ((sIt != sEnd) && (*mIt)->name == (*sIt)->name) { s.newLine() << QString( "%1.copyValues(&theCopyFrom->%1, ignoreMask);") .arg((*mIt)->name); ++sIt; } else { s.newLine() << QString( "if (!(theCopyFrom->%1.state() & ignoreMask))") .arg((*mIt)->name); s.newLine() << "{"; s.newLine(1) << QString("%1 = theCopyFrom->%1;").arg((*mIt)->name); s.newLine() << "}"; } s << endl; } s.newLine() << "return true;"; } QString PropertySetCode::slotMember(const QString &name) { if (!name.isEmpty()) return "&" + name; else return "this"; } QString PropertySetCode::slotMember( const QString &name, const QString &subMember) { if (subMember.isEmpty()) return "&" + name; else return "&" + name + "." + subMember; } void PropertySetCode::generateSlotsConnections( TextStreamIndent &s, const QString &name) const { for (auto it = slots_code.begin(); it != slots_code.end(); ++it) { s.newLine() << QString( "QObject::%1(%2, &QtnProperty::%3, this, &%4::%5);") .arg(name, slotMember(it.value().member), it.key(), selfType, slotName(it.key(), &it.value().member, nullptr)); } for (auto it = members.begin(); it != members.end(); ++it) { if (!(*it)->_extern) continue; for (auto jt = (*it)->slots_code.begin(); jt != (*it)->slots_code.end(); ++jt) { s.newLine() << QString( "QObject::%1(%2, &QtnProperty::%3, this, &%4::%5);") .arg(name, slotMember((*it)->name, jt.value().member), jt.key(), selfType, slotName(jt.key(), &(*it)->name, &jt.value().member)); } } } QVector PropertySetCode::getSubpropertySets() const { QVector _subPropertySets; QVectorIterator> it(subPropertySets); while (it.hasNext()) { const QSharedPointer &ps = it.next(); if (!ps->_extern) _subPropertySets.append(ps.data()); } return _subPropertySets; } EnumCode::EnumCode(const QString &name) : name(name) { } void EnumCode::generateHFile(TextStreamIndent &s) const { s.newLine(); s.newLine() << QString("class %1").arg(name); s.newLine() << "{"; s.newLine() << "public:"; s.addIndent(); if (!items.isEmpty()) { s.newLine() << "enum Enum"; s.newLine() << "{"; s.addIndent(); for (int i = 0, n = items.size(); i < n; ++i) { const EnumItemCode &enumItem = items[i]; s.newLine() << QString("%1 = %2").arg(enumItem.name).arg(enumItem.id); if ((i + 1) != n) s << ","; } s.delIndent(); s.newLine() << "};"; } s.newLine(); s.newLine() << "static const QtnEnumInfo& info();"; s.newLine() << QString("static const unsigned int values_count = %1;") .arg(items.size()); s.delIndent(); s.newLine() << "};"; } void EnumCode::generateCppFile(TextStreamIndent &s) const { s.newLine() << QString("static QtnEnumInfo& create_%1_info()").arg(name); s.newLine() << "{"; s.addIndent(); s.newLine() << "QVector staticValues;"; foreach (const EnumItemCode &enumItem, items) { QString states; if (!enumItem.states.isEmpty()) { states += ", "; for (int i = 0, n = enumItem.states.size(); i < n; ++i) { const QString &state = enumItem.states[i]; if (i != 0) states += " | "; states += "QtnEnumValueState"; states += capitalize(state); } } s.newLine() << QString( "staticValues.append(QtnEnumValueInfo(%1::%2, \"%2\", %3%4));") .arg(name, enumItem.name, enumItem.text, states); } s.newLine(); s.newLine() << QString("static QtnEnumInfo enumInfo(\"%1\", staticValues);") .arg(name); s.newLine() << "return enumInfo;"; s.delIndent(); s.newLine() << "}"; s.newLine(); s.newLine() << QString("const QtnEnumInfo& %1::info()").arg(name); s.newLine() << "{"; s.addIndent(); s.newLine() << QString("static QtnEnumInfo& enumInfo = create_%1_info();") .arg(name); s.newLine() << "return enumInfo;"; s.delIndent(); s.newLine() << "}"; } PegContext::PegContext() : currPropertySet(nullptr) , currProperty(nullptr) { } PropertySetMemberCode *PegContext::current() { if (currProperty) return currProperty; else { if (!currPropertySet) peg.fatalError("No current object."); return currPropertySet; } } QString PegContext::currentType() const { if (currType.namespaceName.isEmpty()) return currType.name; else return currType.namespaceName + "::" + currType.name; } QString PegContext::currentPropertyType() const { QString res = "QtnProperty" + currType.name; if (!currType.namespaceName.isEmpty()) res = currType.namespaceName + "::" + res; return res; } QString PegContext::currentPropertySetType() const { QString res = "QtnPropertySet" + currType.name; if (!currType.namespaceName.isEmpty()) res = currType.namespaceName + "::" + res; return res; } void PegContext::startPropertySet() { QSharedPointer newPropertySet(new PropertySetCode()); if (!propertySet) { propertySet = newPropertySet; subPropertySets.push(propertySet.data()); } else { Q_ASSERT(!subPropertySets.isEmpty()); PropertySetCode *currentPropertySet = subPropertySets.top(); newPropertySet->setSuperType(currentPropertySet); currentPropertySet->subPropertySets.append(newPropertySet); subPropertySets.push(newPropertySet.data()); } currPropertySet = subPropertySets.top(); } void PegContext::commitPropertySet() { subPropertySets.pop(); if (subPropertySets.isEmpty()) { peg.code.append(propertySet); propertySet.reset(); currPropertySet = nullptr; } else { currPropertySet = subPropertySets.top(); } } void PegContext::startProperty() { QSharedPointer newProperty(new PropertyCode()); currPropertySet->members.append(newProperty); currProperty = newProperty.data(); } void PegContext::commitProperty() { currProperty = nullptr; } bool PegContext::checkSlotName(const QString &name) { return slotsSignatures.contains(name); } PegContext pegContext; PEG &PEG::instance() { static PEG peg; return peg; } PEG::PEG() : m_isValid(false) , m_errStream(stderr) { } bool PEG::start(QString hFileName, QString cppFileName) { if (m_isValid) { printError("PEG initialized already"); return false; } QScopedPointer hFile(new QFile(hFileName, this)); if (!hFile->open(QFile::WriteOnly | QFile::Truncate)) { printError( QString("Cannot open '%1' file for writting").arg(hFileName)); return false; } QScopedPointer cppFile(new QFile(cppFileName, this)); if (!cppFile->open(QFile::WriteOnly | QFile::Truncate)) { printError( QString("Cannot open '%1' file for writting").arg(cppFileName)); return false; } QFileInfo fi(*hFile); m_hFileName = fi.completeBaseName() + "." + fi.suffix(); m_hDefine = fi.baseName().toUpper() + "_" + fi.suffix().toUpper(); m_hStream.setDevice(hFile.take()); m_cppStream.setDevice(cppFile.take()); m_isValid = true; return true; } void PEG::stop() { generateOutputs(); code.clear(); m_isValid = false; } void PEG::printError(QString error) { m_errStream << error << endl; } void PEG::fatalError(QString error) { printError(error); exit(1); } void PEG::generateOutputs() { generateHFile(); generateCppFile(); } void PEG::generateHFile() { m_hStream << "#ifndef " << m_hDefine << endl; m_hStream << "#define " << m_hDefine << endl; for (auto it = code.begin(); it != code.end(); ++it) { (*it)->generateHFile(m_hStream); } m_hStream << endl << endl; m_hStream << "#endif // " << m_hDefine << endl; } void PEG::generateCppFile() { m_cppStream << "#include \"" << m_hFileName << "\"" << endl; for (auto it = code.begin(); it != code.end(); ++it) { (*it)->generateCppFile(m_cppStream); } m_cppStream << endl; } /* void PEG::addIncludeH(QString name) { QSharedPointer code(new IncludeCode(name, true)); m_code.push_back(code); } void PEG::addIncludeCpp(QString name) { QSharedPointer code(new IncludeCode(name, false)); m_code.push_back(code); } void PEG::startPropertySet(QString name, QString parentType) { Q_ASSERT(!m_context->propertySet); m_context->propertySet.reset(new PropertySetCode(name, parentType)); } void PEG::commitPropertySet() { Q_ASSERT(m_context->propertySet); m_code.push_back(m_context->propertySet); m_context->propertySet.reset(); } void PEG::startProperty(QString name, QString type) { Q_ASSERT(!m_context->property); Q_ASSERT(m_context->propertySet); m_context->property.reset(new PropertyCode()); m_context->property->name = name; m_context->property->type = type; } void PEG::commitProperty() { Q_ASSERT(m_context->propertySet); Q_ASSERT(m_context->property); m_context->propertySet->properties.push_back(m_context->property); m_context->property.reset(); } void PEG::addAssignment(QString name, QString value) { if (name.isEmpty()) fatalError("Assignment name is empty."); if (value.isEmpty()) fatalError("Assignment value is empty"); if (m_context->property) m_context->property->assignments.insert(name.trimmed(), value.trimmed()); else if (m_context->propertySet) m_context->propertySet->assignments.insert(name.trimmed(), value.trimmed()); else fatalError("Assignment is out of scope."); } */ ================================================ FILE: PEG/PropertyEnumGenerator.h ================================================ /* Copyright (c) 2012-2016 Alex Zhondin Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #ifndef PROPERTY_ENUM_GENERATOR_H #define PROPERTY_ENUM_GENERATOR_H #include #include #include #include #include #include class TextStreamIndent: public QTextStream { public: TextStreamIndent() : m_indent(0) { } QTextStream& newLine(int indentOffset = 0) { if (!m_wrapperLines.isEmpty()) { auto& info = m_wrapperLines.top(); if (!info.active) { info.active = true; newLine(); newLine(info.indentOffset) << info.firstLine; } } return *this << endl << QString(TAB_LEN*(m_indent+indentOffset), ' '); } void addIndent() { ++m_indent; } void delIndent() { --m_indent; } void pushWrapperLines(const QString& firstLine, const QString& lastLine, int indentOffset = 0) { WrapperLinesInfo info; info.firstLine = firstLine; info.lastLine = lastLine; info.indentOffset = indentOffset; m_wrapperLines.push(info); } bool popWrapperLines() { Q_ASSERT(!m_wrapperLines.isEmpty()); auto info = m_wrapperLines.pop(); if (info.active && !info.lastLine.isEmpty()) newLine(info.indentOffset) << info.lastLine; return info.active; } private: int m_indent; static const int TAB_LEN = 4; struct WrapperLinesInfo { QString firstLine; QString lastLine; int indentOffset; bool active; WrapperLinesInfo(): indentOffset(0), active(false) {} }; QStack m_wrapperLines; }; class Code { Q_DISABLE_COPY(Code) public: Code() {} virtual ~Code() {} virtual void generateHFile(TextStreamIndent& s) const = 0; virtual void generateCppFile(TextStreamIndent& s) const = 0; }; class PEG: public QObject { Q_OBJECT Q_DISABLE_COPY(PEG) public: ~PEG() {} static PEG& instance(); bool start(QString hFileName, QString cppFileName); void stop(); void fatalError(QString error); QVector > code; private: PEG(); bool isValid() const { return m_isValid; } void printError(QString error); void generateOutputs(); void generateHFile(); void generateCppFile(); bool m_isValid; QString m_hFileName; QString m_hDefine; TextStreamIndent m_hStream; TextStreamIndent m_cppStream; QTextStream m_errStream; }; QString propertyType(QString type); extern PEG& peg; // types struct AssignInfo { QString member; QString value; }; struct SignatureInfo { QString arguments; QString unusedCode; }; // key - setter name (without set) // value - setter parameter typedef QMap Assignments; // key - slot name // values - slot code typedef QMap Slots; typedef QMap Signatures; // key - name exception typedef QSet Exceptions; struct DelegateInfo { QString name; QMap attributes; void generateCode(TextStreamIndent& s) const; }; // code for #include constructions struct IncludeCode: public Code { QString name; bool isHeader; IncludeCode(QString name, bool isHeader); void generateHFile(TextStreamIndent& s) const override; void generateCppFile(TextStreamIndent& s) const override; private: void generate(TextStreamIndent& s) const { s.newLine() << "#include " << name; } Q_DISABLE_COPY(IncludeCode) }; // code for plain C++ code struct SourceCode: public Code { QString code; bool code_h; SourceCode(const QString& code, bool code_h); void generateHFile(TextStreamIndent& s) const override; void generateCppFile(TextStreamIndent& s) const override; }; struct PropertySetMemberCode { PropertySetMemberCode(): _extern(false) {} virtual ~PropertySetMemberCode() {} QString name; QString selfType; Assignments assignments; Slots slots_code; bool _extern; QScopedPointer delegateInfo; }; // code for property struct PropertyCode: public PropertySetMemberCode { PropertyCode() { _extern = true; } }; // code for property_set struct PropertySetCode: public Code, public PropertySetMemberCode { QVector> members; QVector> subPropertySets; QVector> sourceCodes; QString superType; struct Constructor { QString code; QString initialization_list; }; QScopedPointer constructor; struct Destructor { QString code; }; QScopedPointer destructor; PropertySetCode(); void setName(QString _name); void setSuperType(const PropertySetCode* parent); void setConstructorCode(QString _name,QString _initialization_list, QString _code); void setDestructorCode(QString _name, QString _code); void generateHFile(TextStreamIndent& s) const override; void generateCppFile(TextStreamIndent& s) const override; private: QString constructorParamsList() const; void generateChildrenDeclaration(TextStreamIndent& s) const; void generateChildrenInitialization(TextStreamIndent& s) const; void generateChildrenAssignment(TextStreamIndent& s) const; void generateChildrenCopy(TextStreamIndent& s) const; void generateSubPropertySetsDeclarations(TextStreamIndent& s) const; void generateSubPropertySetsImplementations(TextStreamIndent& s) const; void generateSlotsDeclaration(TextStreamIndent& s) const; void generateSlotsImplementation(TextStreamIndent& s) const; void generateHSourceCode(TextStreamIndent& s) const; void generateCppSourceCode(TextStreamIndent& s) const; void generateDelegatesConnection(TextStreamIndent& s) const; void generateConstructorInitializationList(TextStreamIndent& s) const; void generateCopyValues(TextStreamIndent& s) const; static QString slotMember(const QString& name); static QString slotMember(const QString& name, const QString& subMember); void generateSlotsConnections(TextStreamIndent& s, const QString& name) const; QVector getSubpropertySets() const; }; // code for enums struct EnumCode: public Code { QString name; struct EnumItemCode { QString name; int id; QString text; QVector states; }; QVector items; EnumCode(const QString& name); void generateHFile(TextStreamIndent& s) const override; void generateCppFile(TextStreamIndent& s) const override; }; struct PegContext { QSharedPointer propertySet; QStack subPropertySets; PropertySetCode *currPropertySet; PropertyCode *currProperty; QString currAssignMember; QString currAssignFunc; QSharedPointer enumCode; struct TypeInfo { QString namespaceName; QString name; }; TypeInfo currType; PegContext(); PropertySetMemberCode *current(); QString currentType() const; QString currentPropertyType() const; QString currentPropertySetType() const; void startPropertySet(); void commitPropertySet(); void startProperty(); void commitProperty(); bool checkSlotName(const QString& name); private: Q_DISABLE_COPY(PegContext) }; extern PegContext pegContext; #endif // PROPERTY_ENUM_GENERATOR_H ================================================ FILE: PEG/PropertyEnumGeneratorCommon.h ================================================ /* Copyright (c) 2012-2016 Alex Zhondin Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #ifndef PROPERTY_ENUM_GENERATOR_COMMON_H #define PROPERTY_ENUM_GENERATOR_COMMON_H #include #define YYSTYPE QString struct YYLTYPE; extern int yylex(YYSTYPE* yylval_param, YYLTYPE* yylloc_param); #endif // PROPERTY_ENUM_GENERATOR_COMMON_H ================================================ FILE: PEG/main.cpp ================================================ /* Copyright (c) 2012-2016 Alex Zhondin Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include "PropertyEnumGenerator.h" #include #include #include extern int yyparse(); extern FILE *yyin; extern int yydebug; int main(int argc, char *argv[]) { //yydebug = 1; // Qt application QCoreApplication app(argc, argv); app.setAttribute(Qt::AA_Use96Dpi, true); // check argument if (argc < 2 || argc > 4) { QTextStream(stdout) << QString("peg usage: peg [ [h output file]]") << endl; return 0; } // generate output file names const char *inputFileName = argv[1]; QFileInfo fi(inputFileName); if (!fi.exists()) { QTextStream(stderr) << QString("Error: file '%1' doesn't exist") .arg(fi.absoluteFilePath()) << endl; return 1; } QString cppFileName; if (argc < 3) { cppFileName = fi.path() + "/" + fi.completeBaseName() + ".peg.cpp"; } else { cppFileName = argv[2]; } QString hFileName; if (argc < 3) { hFileName = fi.path() + "/" + fi.completeBaseName() + ".peg.h"; } else if (argc < 4) { hFileName = cppFileName; hFileName.replace(QRegExp(".cpp$"), ".h"); } else { hFileName = argv[3]; } PEG &peg = PEG::instance(); if (!peg.start(hFileName, cppFileName)) return 1; // open source file for reading FILE *input_file = fopen(inputFileName, "r"); if (!input_file) { QTextStream(stderr) << QString("Error: cannot open file '%1' for reading") .arg(inputFileName) << endl; return 1; } yyin = input_file; int result = yyparse(); yyin = stdin; fclose(input_file); peg.stop(); return result; } ================================================ FILE: QtnProperty/Auxiliary/PropertyAux.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_PROPERTY_AUX_H #define QTN_PROPERTY_AUX_H #include "QtnProperty/Config.h" #include // forward declarations class QtnPropertyBase; class QtnProperty; class QtnPropertySet; enum QtnPropertyStateFlag { QtnPropertyStateNone = 0x0000, QtnPropertyStateNonSimple = 0x0001, QtnPropertyStateInvisible = 0x0002, QtnPropertyStateImmutable = 0x0004, QtnPropertyStateCollapsed = 0x0008, QtnPropertyStateNonSerialized = 0x0010, QtnPropertyStateMultiValue = 0x0020, QtnPropertyStateModifiedValue = 0x0040, QtnPropertyStateIgnoreDirectParentState = 0x80, QtnPropertyStateResettable = 0x100, QtnPropertyStateUnlockable = 0x200 }; Q_DECLARE_FLAGS(QtnPropertyState, QtnPropertyStateFlag) Q_DECLARE_OPERATORS_FOR_FLAGS(QtnPropertyState) enum QtnPropertyChangeReasonFlag { QtnPropertyChangeReasonNewValue = 0x0001, QtnPropertyChangeReasonLoadedValue = 0x0002, QtnPropertyChangeReasonName = 0x0004, QtnPropertyChangeReasonDisplayName = 0x0008, QtnPropertyChangeReasonDescription = 0x0010, QtnPropertyChangeReasonId = 0x0020, QtnPropertyChangeReasonStateLocal = 0x0040, QtnPropertyChangeReasonStateInherited = 0x0080, QtnPropertyChangeReasonChildPropertyAdd = 0x0100, QtnPropertyChangeReasonChildPropertyRemove = 0x0200, QtnPropertyChangeReasonEdit = 0x0400, QtnPropertyChangeReasonResetValue = 0x0800, QtnPropertyChangeReasonMultiEdit = 0x1000, QtnPropertyChangeReasonLockToggled = 0x2000, QtnPropertyChangeReasonUpdateDelegate = 0x4000, QtnPropertyChangeReasonState = QtnPropertyChangeReasonStateLocal | QtnPropertyChangeReasonStateInherited, QtnPropertyChangeReasonChildren = QtnPropertyChangeReasonChildPropertyAdd | QtnPropertyChangeReasonChildPropertyRemove, QtnPropertyChangeReasonValue = QtnPropertyChangeReasonNewValue | QtnPropertyChangeReasonLoadedValue | QtnPropertyChangeReasonResetValue, }; Q_DECLARE_FLAGS(QtnPropertyChangeReason, QtnPropertyChangeReasonFlag) Q_DECLARE_OPERATORS_FOR_FLAGS(QtnPropertyChangeReason) typedef qint32 QtnPropertyID; extern QTN_IMPORT_EXPORT const qint32 QtnPropertyIDInvalid; typedef void *QtnPropertyValuePtr; template inline T *qtnCastPropertyValue(QtnPropertyValuePtr value) { return reinterpret_cast(value); } template inline const T *qtnConstCastPropertyValue(QtnPropertyValuePtr value) { return reinterpret_cast(value); } Q_DECLARE_METATYPE(QtnPropertyID) Q_DECLARE_METATYPE(QtnPropertyState) Q_DECLARE_METATYPE(QtnPropertyChangeReason) Q_DECLARE_METATYPE(QtnPropertyValuePtr) #endif // QTN_PROPERTY_AUX_H ================================================ FILE: QtnProperty/Auxiliary/PropertyDelegateInfo.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateInfo.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include "PropertyMacro.h" QtnPropertyDelegateInfo::QtnPropertyDelegateInfo( const QtnPropertyDelegateInfo &other) : name(other.name) , attributes(other.attributes) { } QtnPropertyDelegateInfo::QtnPropertyDelegateInfo( const QByteArray &name, const Attributes &attributes) : name(name) , attributes(attributes) { } QByteArray qtnComboBoxDelegate() { return QByteArrayLiteral("ComboBox"); } QByteArray qtnCheckBoxDelegate() { return QByteArrayLiteral("CheckBox"); } QByteArray qtnFieldDelegateNameAttr() { return QByteArrayLiteral("fieldDelegateName"); } double qtnHundredPercent(double value) { return std::max(0.0, std::min(100.0, value)); } ================================================ FILE: QtnProperty/Auxiliary/PropertyDelegateInfo.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_PROPERTY_DELEGATE_INFO_H #define QTN_PROPERTY_DELEGATE_INFO_H #include "QtnProperty/Config.h" #include #include struct QTN_IMPORT_EXPORT QtnPropertyDelegateInfo { QByteArray name; using Attributes = QMap; Attributes attributes; QtnPropertyDelegateInfo() = default; QtnPropertyDelegateInfo(const QtnPropertyDelegateInfo &other); QtnPropertyDelegateInfo( const QByteArray &name, const Attributes &attributes = Attributes()); template inline T getAttribute( const QByteArray &attributeName, const T &defaultValue = T()) const { auto it = attributes.find(attributeName); if (it == attributes.end()) return defaultValue; return it.value().value(); } template inline bool loadAttribute(const QByteArray &name, T &to) const { auto it = attributes.find(name); if (it == attributes.end()) return false; to = it.value().value(); return true; } template inline void storeAttributeValue(const QByteArray &name, OBJ_T *to, ATTR_T_RET (OBJ_T::*get)() const, void (OBJ_T::*set)(ATTR_T_ARG)) const { Q_ASSERT(to); (to->*set)(getAttribute(name, (to->*get)())); } }; struct QTN_IMPORT_EXPORT QtnSubPropertyInfo { int id; QString key; QByteArray displayNameAttr; QByteArray descriptionAttr; }; #endif // QTN_PROPERTY_DELEGATE_INFO_H ================================================ FILE: QtnProperty/Auxiliary/PropertyMacro.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYMACRO_H #define PROPERTYMACRO_H #define P_PROPERTY_DECL_CMP_OPERATOR(ClassName, ValueType, Op) \ inline bool operator Op(const ClassName &left, const ClassName &right) \ { \ return left.value() Op right.value(); \ } \ inline bool operator Op(const ClassName &left, ValueType right) \ { \ return left.value() Op right; \ } \ inline bool operator Op(ValueType left, const ClassName &right) \ { \ return left Op right.value(); \ } #define P_PROPERTY_DECL_EQ_OPERATORS(ClassName, ValueType) \ P_PROPERTY_DECL_CMP_OPERATOR(ClassName, ValueType, ==) \ P_PROPERTY_DECL_CMP_OPERATOR(ClassName, ValueType, !=) #define P_PROPERTY_DECL_ALL_OPERATORS(ClassName, ValueType) \ P_PROPERTY_DECL_EQ_OPERATORS(ClassName, ValueType) \ P_PROPERTY_DECL_CMP_OPERATOR(ClassName, ValueType, <) \ P_PROPERTY_DECL_CMP_OPERATOR(ClassName, ValueType, <=) \ P_PROPERTY_DECL_CMP_OPERATOR(ClassName, ValueType, >) \ P_PROPERTY_DECL_CMP_OPERATOR(ClassName, ValueType, >=) #define P_PROPERTY_DECL_MEMBER_OPERATORS(ClassName) \ public: \ operator ValueType() const \ { \ return value(); \ } \ ClassName &operator=(const ClassName &newValue) \ { \ setValue(newValue.value()); \ return *this; \ } \ ClassName &operator=(ValueType newValue) \ { \ setValue(newValue); \ return *this; \ } #define P_PROPERTY_DECL_MEMBER_OPERATORS2(ClassName, BaseClassName) \ public: \ operator ValueType() const \ { \ return value(); \ } \ ClassName &operator=(const ClassName &newValue) \ { \ setValue(newValue.value()); \ return *this; \ } \ ClassName &operator=(const BaseClassName &newValue) \ { \ setValue(newValue.value()); \ return *this; \ } \ ClassName &operator=(ValueType newValue) \ { \ setValue(newValue); \ return *this; \ } #endif // PROPERTYMACRO_H ================================================ FILE: QtnProperty/Auxiliary/PropertyTemplates.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_TEMPLATES_H #define PROPERTY_TEMPLATES_H #include "QtnProperty/Property.h" #include "PropertyMacro.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include #include template struct PropertyValueTag {}; template > class QtnSinglePropertyBase : public QtnProperty { public: using ValueType = T; using ValueTypeStore = typename std::decay::type; using ValueTag = PropertyValueTag>; inline ValueType value() const { return valueImpl(ValueTag()); } bool setValue(ValueType newValue, QtnPropertyChangeReason reason = QtnPropertyChangeReason()) { if ((reason & QtnPropertyChangeReasonEdit) && !isEditableByUser()) { return false; } if (!isWritable() || !isValueAcceptedImpl(newValue)) return false; if (!(reason & QtnPropertyChangeReasonMultiEdit) && isValueEqualImpl(newValue)) { return true; } bool accept = true; emit propertyValueAccept(QtnPropertyValuePtr(&newValue), &accept); if (!accept) return false; if (!(reason & QtnPropertyChangeReasonValue)) { reason |= QtnPropertyChangeReasonNewValue; } emit propertyWillChange(reason, QtnPropertyValuePtr(&newValue), qMetaTypeId()); setValueImpl(newValue, reason); emit propertyDidChange(reason); return true; } inline operator ValueType() const { return value(); } inline QtnSinglePropertyBase &operator=(ValueType newValue) { setValue(newValue); return *this; } inline QtnSinglePropertyBase &operator=( const QtnSinglePropertyBase &newValue) { setValue(newValue.value()); return *this; } inline bool readDefaultValue(ValueTypeStore &to) const { return defaultValueImpl(to); } protected: explicit QtnSinglePropertyBase(QObject *parent) : QtnProperty(parent) { } virtual void doReset(QtnPropertyChangeReason reason) override { Q_ASSERT(reason & QtnPropertyChangeReasonResetValue); ValueTypeStore defaultValue; if (defaultValueImpl(defaultValue)) { setValue(defaultValue, reason); } else { QtnProperty::doReset(reason); } } virtual ValueType valueImpl(ValueTag) const = 0; virtual void setValueImpl( ValueType newValue, QtnPropertyChangeReason reason) = 0; virtual bool isValueAcceptedImpl(ValueType) { return true; } virtual bool defaultValueImpl(ValueTypeStore &to) const { Q_UNUSED(to); return false; } virtual bool isValueEqualImpl(ValueType valueToCompare) { return EqPred()(valueToCompare, value()); } // serialization implementation virtual bool loadImpl(QDataStream &stream) override { if (!QtnProperty::loadImpl(stream)) return false; ValueTypeStore newValue; stream >> newValue; if (stream.status() != QDataStream::Ok) return false; setValue(newValue, QtnPropertyChangeReasonLoadedValue); return stream.status() == QDataStream::Ok; } virtual bool saveImpl(QDataStream &stream) const override { if (!QtnProperty::saveImpl(stream)) return false; stream << value(); return stream.status() == QDataStream::Ok; } // variant conversion implementation virtual bool fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) override { if (var.canConvert()) return setValue(var.value(), reason); return QtnProperty::fromVariantImpl(var, reason); } virtual bool toVariantImpl(QVariant &var) const override { var.setValue(value()); return var.isValid(); } private: QtnSinglePropertyBase(const QtnSinglePropertyBase &) Q_DECL_EQ_DELETE; }; /* template class QtnSinglePropertyBaseAsImpl : public QtnSinglePropertyBaseType { public: using BaseValueType = typename QtnSinglePropertyBaseType::ValueType; using BaseValueTypeStore = typename QtnSinglePropertyBaseType::ValueTypeStore; protected: virtual BaseValueType valueBaseImpl() const = 0; virtual void setValueBaseImpl(BaseValueType newValue, QtnPropertyChangeReason reason) = 0; private: BaseValueType valueImpl() const final { return valueBaseImpl(); } void setValueImpl(BaseValueType newValue, QtnPropertyChangeReason reason) final { setValueBaseImpl(std::move(newValue), reason); } }; */ template > class QtnSinglePropertyBaseAs : public QtnSinglePropertyBaseType { public: using ThisPropertyType = QtnSinglePropertyBaseAs; using BasePropertyType = QtnSinglePropertyBaseType; using BaseValueType = typename QtnSinglePropertyBaseType::ValueType; using BaseValueTypeStore = typename QtnSinglePropertyBaseType::ValueTypeStore; using BaseValueTag = typename QtnSinglePropertyBaseType::ValueTag; using ValueType = ActualValueType; using ValueTypeStore = typename std::decay::type; using ValueTag = PropertyValueTag; inline ValueType value() const { return valueImpl(ValueTag()); } bool setValue(ValueType newValue, QtnPropertyChangeReason reason = QtnPropertyChangeReason()) { BaseValueTypeStore baseValue = BaseValueTypeStore(); if (!fromActualValue(std::move(newValue), baseValue)) return false; return BasePropertyType::setValue(baseValue, reason); } inline operator ValueType() const { return value(); } inline ThisPropertyType &operator=(ValueType newValue) { setValue(newValue); return *this; } inline ThisPropertyType &operator=(const ThisPropertyType &newValue) { setValue(newValue.value()); return *this; } protected: explicit QtnSinglePropertyBaseAs(QObject *parent) : BasePropertyType(parent) { } virtual bool fromActualValue(ValueType actualValue, BaseValueTypeStore& baseValue) const = 0; virtual bool toActualValue(ValueTypeStore& actualValue, BaseValueType baseValue) const = 0; virtual ValueType valueImpl(ValueTag) const = 0; virtual void setValueImpl(ValueType newValue, QtnPropertyChangeReason reason) = 0; virtual bool isValueAcceptedImpl(ValueType) { return true; } virtual bool defaultValueImpl(ValueTypeStore &to) const { Q_UNUSED(to); return false; } virtual bool isValueEqualImpl(ValueType valueToCompare) { return EqPred()(valueToCompare, value()); } BaseValueType valueImpl(BaseValueTag) const override { BaseValueTypeStore baseValue = BaseValueTypeStore(); fromActualValue(value(), baseValue); return baseValue; } virtual bool isValueAcceptedImpl(BaseValueType valueToAccept) override { ValueTypeStore value = ValueTypeStore(); toActualValue(value, std::move(valueToAccept)); return isValueAcceptedImpl(std::move(value)); } virtual bool isValueEqualImpl(BaseValueType valueToCompare) override { ValueTypeStore value = ValueTypeStore(); toActualValue(value, std::move(valueToCompare)); return isValueEqualImpl(std::move(value)); } virtual bool defaultValueImpl(BaseValueTypeStore &to) const override { ValueTypeStore value = ValueTypeStore(); if (defaultValueImpl(value)) return fromActualValue(value, to); return false; } private: void setValueImpl( BaseValueType newValue, QtnPropertyChangeReason reason) override { ValueTypeStore value = ValueTypeStore(); toActualValue(value, std::move(newValue)); setValueImpl(std::move(value), reason); } }; template class QtnSinglePropertyValue : public QtnSinglePropertyType { public: using ValueType = typename QtnSinglePropertyType::ValueType; using ValueTypeStore = typename QtnSinglePropertyType::ValueTypeStore; using ValueTag = typename QtnSinglePropertyType::ValueTag; protected: explicit QtnSinglePropertyValue(QObject *parent) : QtnSinglePropertyType(parent) , m_value(ValueTypeStore()) { } ValueType valueImpl(ValueTag) const override { return m_value; } void setValueImpl( ValueType newValue, QtnPropertyChangeReason /*reason*/) override { m_value = newValue; } private: ValueTypeStore m_value; Q_DISABLE_COPY(QtnSinglePropertyValue) }; template class QtnSinglePropertyCallback : public QtnSinglePropertyType { public: using ValueType = typename QtnSinglePropertyType::ValueType; using ValueTypeStore = typename QtnSinglePropertyType::ValueTypeStore; using ValueTag = typename QtnSinglePropertyType::ValueTag; using CallbackValueGet = std::function; using CallbackValueSet = std::function; using CallbackValueAccepted = std::function; using CallbackValueEqual = std::function; inline const CallbackValueGet &callbackValueDefault() const { return m_callbackValueDefault; } inline const CallbackValueGet &callbackValueGet() const { return m_callbackValueGet; } inline const CallbackValueSet &callbackValueSet() const { return m_callbackValueSet; } inline const CallbackValueAccepted &callbackValueAccepted() const { return m_callbackValueAccepted; } inline const CallbackValueEqual &callbackValueEqual() const { return m_callbackValueEqual; } inline void setCallbackValueDefault(const CallbackValueGet &callback) { m_callbackValueDefault = callback; this->switchState(QtnPropertyStateResettable, callback != nullptr); } inline void setCallbackValueGet(const CallbackValueGet &callback) { m_callbackValueGet = callback; } inline void setCallbackValueSet(const CallbackValueSet &callback) { m_callbackValueSet = callback; this->switchState(QtnPropertyStateImmutable, callback == nullptr); } inline void setCallbackValueAccepted(const CallbackValueAccepted &callback) { m_callbackValueAccepted = callback; } inline void setCallbackValueEqual(const CallbackValueEqual &callback) { m_callbackValueEqual = callback; } protected: explicit QtnSinglePropertyCallback(QObject *parent) : QtnSinglePropertyType(parent) { } virtual ValueType valueImpl(ValueTag) const override { Q_ASSERT(m_callbackValueGet); return m_callbackValueGet(); } virtual void setValueImpl( ValueType newValue, QtnPropertyChangeReason reason) override { Q_ASSERT(m_callbackValueSet); m_callbackValueSet(newValue, reason); } virtual bool isValueAcceptedImpl(ValueType valueToAccept) override { if (m_callbackValueAccepted) return m_callbackValueAccepted(valueToAccept); return QtnSinglePropertyType::isValueAcceptedImpl(valueToAccept); } virtual bool isValueEqualImpl(ValueType valueToCompare) override { if (m_callbackValueEqual) return m_callbackValueEqual(valueToCompare); return QtnSinglePropertyType::isValueEqualImpl(valueToCompare); } virtual bool defaultValueImpl(ValueTypeStore &to) const override { if (m_callbackValueDefault) { to = m_callbackValueDefault(); return true; } return false; } private: Q_DISABLE_COPY(QtnSinglePropertyCallback) CallbackValueGet m_callbackValueDefault; CallbackValueGet m_callbackValueGet; CallbackValueSet m_callbackValueSet; CallbackValueAccepted m_callbackValueAccepted; CallbackValueEqual m_callbackValueEqual; }; template class QtnNumericPropertyBase : public QtnSinglePropertyType { template struct interval_t { }; template struct interval_t::value>::type> { using type = double; using maxsigned = double; }; template struct interval_t::value>::type> { using type = typename std::make_unsigned::type; using maxsigned = qint64; }; public: using ValueType = typename QtnSinglePropertyType::ValueType; using IntervalType = typename interval_t::type; using SignedMaxType = typename interval_t::maxsigned; using MaxIntervalType = typename interval_t::type; inline ValueType value() const { return correctValue(QtnSinglePropertyType::value()); } inline ValueType minValue() const { return m_minValue; } inline void setMinValue(ValueType minValue) { if (m_minValue == minValue) return; emit this->propertyWillChange( QtnPropertyChangeReasonNewValue, nullptr, 0); m_minValue = minValue; m_maxValue = std::max(m_minValue, m_maxValue); emit this->propertyDidChange(QtnPropertyChangeReasonNewValue); } inline ValueType maxValue() const { return m_maxValue; } inline void setMaxValue(ValueType maxValue) { if (maxValue == m_maxValue) return; emit this->propertyWillChange( QtnPropertyChangeReasonNewValue, nullptr, 0); m_maxValue = maxValue; m_minValue = std::min(m_minValue, m_maxValue); emit this->propertyDidChange(QtnPropertyChangeReasonNewValue); } inline ValueType correctValue(ValueType value) const { if (value < m_minValue) value = m_minValue; if (value > m_maxValue) value = m_maxValue; return value; } inline ValueType stepValue() const { return m_stepValue; } inline void setStepValue(ValueType stepValue) { if (stepValue == m_stepValue) return; emit this->propertyWillChange( QtnPropertyChangeReasonStateLocal, nullptr, 0); m_stepValue = stepValue; emit this->propertyDidChange(QtnPropertyChangeReasonStateLocal); } inline void incrementValue( QtnPropertyChangeReason reason = QtnPropertyChangeReasonNewValue, int steps = 1) { auto oldValue = this->value(); ValueType newValue; auto step = SignedMaxType(m_stepValue) * steps; if (step < SignedMaxType(0) && MaxIntervalType(-step) >= IntervalType(oldValue - m_minValue)) { newValue = m_minValue; } else if (step > SignedMaxType(0) && MaxIntervalType(step) >= IntervalType(m_maxValue - oldValue)) { newValue = m_maxValue; } else { newValue = oldValue + step; } this->setValue(newValue, reason); } protected: explicit QtnNumericPropertyBase(QObject *parent) : QtnSinglePropertyType(parent) , m_minValue(std::numeric_limits::lowest()) , m_maxValue(std::numeric_limits::max()) , m_stepValue(ValueType(1)) { } virtual bool isValueAcceptedImpl(ValueType valueToAccept) override { if (valueToAccept < m_minValue) return false; if (valueToAccept > m_maxValue) return false; return true; } private: ValueType m_minValue; ValueType m_maxValue; ValueType m_stepValue; Q_DISABLE_COPY(QtnNumericPropertyBase) }; template inline void qtnMakePercentProperty(T *dProp, typename T::ValueType (*AfterGet)(typename T::ValueType), const QByteArray &delegateName = QByteArray()) { using ValueType = typename T::ValueType; auto prevGet = dProp->callbackValueGet(); if (prevGet) { dProp->setCallbackValueGet([prevGet, AfterGet]() -> ValueType { return AfterGet(prevGet() * 100.0); }); } auto prevEqual = dProp->callbackValueEqual(); if (prevEqual) { dProp->setCallbackValueEqual([prevEqual](ValueType value) -> bool { return prevEqual(value / 100.0); }); } auto prevSet = dProp->callbackValueSet(); if (prevSet) { dProp->setCallbackValueSet( [prevSet](ValueType value, QtnPropertyChangeReason reason) { prevSet(value / 100.0, reason); }); } auto prevDefault = dProp->callbackValueDefault(); if (prevDefault) { dProp->setCallbackValueDefault([prevDefault, AfterGet]() -> ValueType { return AfterGet(prevDefault() * 100.0); }); } QtnPropertyDelegateInfo delegate; qtnInitPercentSpinBoxDelegate(delegate); if (!delegateName.isEmpty()) delegate.name = delegateName; dProp->setDelegateInfo(delegate); } template class QtnNumericPropertyValue : public QtnSinglePropertyType { public: using ValueType = typename QtnSinglePropertyType::ValueType; using ValueTag = typename QtnSinglePropertyType::ValueTag; inline ValueType defaultValue() const { return m_defaultValue; } inline void setDefaultValue(ValueType defaultValue) { m_defaultValue = defaultValue; } protected: explicit QtnNumericPropertyValue(QObject *parent) : QtnSinglePropertyType(parent) , m_value(ValueType(0)) , m_defaultValue(ValueType(0)) { this->addState(QtnPropertyStateResettable); } virtual bool defaultValueImpl(ValueType &to) const override { to = this->correctValue(m_defaultValue); return true; } virtual ValueType valueImpl(ValueTag) const override { return m_value; } virtual void setValueImpl( ValueType newValue, QtnPropertyChangeReason /*reason*/) override { m_value = newValue; } private: ValueType m_value; ValueType m_defaultValue; Q_DISABLE_COPY(QtnNumericPropertyValue) }; template class QTN_IMPORT_EXPORT QtnSinglePropertyBase; template class QTN_IMPORT_EXPORT QtnSinglePropertyBase; template class QTN_IMPORT_EXPORT QtnSinglePropertyBase; template class QTN_IMPORT_EXPORT QtnSinglePropertyBase; template class QTN_IMPORT_EXPORT QtnSinglePropertyBase; template class QTN_IMPORT_EXPORT QtnSinglePropertyBase; template class QTN_IMPORT_EXPORT QtnSinglePropertyBase; template class QTN_IMPORT_EXPORT QtnSinglePropertyBase; template class QTN_IMPORT_EXPORT QtnSinglePropertyBase; #endif // PROPERTY_TEMPLATES_H ================================================ FILE: QtnProperty/Config.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include #if defined(QTN_DYNAMIC_LIBRARY) #define QTN_IMPORT_EXPORT Q_DECL_EXPORT #elif defined(QTN_DYNAMIC_IMPORT) #define QTN_IMPORT_EXPORT Q_DECL_IMPORT #else #define QTN_IMPORT_EXPORT #ifndef QTN_STATIC_LIBRARY #define QTN_STATIC_LIBRARY #endif #endif #define PERCENT_SUFFIX 1 #define DEGREE_SUFFIX 2 ================================================ FILE: QtnProperty/Core/PropertyBool.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyBool.h" #include static bool getBoolValue(QString boolText, bool &success) { success = true; if (boolText.compare(QtnPropertyBool::getBoolText(false, true), Qt::CaseInsensitive) == 0) return false; if (boolText.compare( QtnPropertyBool::getBoolText(true, true), Qt::CaseInsensitive) == 0) return true; if (boolText.toULongLong(&success) != 0) return true; success = false; return false; } QtnPropertyBoolBase::QtnPropertyBoolBase(QObject *parent) : QtnSinglePropertyBase(parent) { } bool QtnPropertyBoolBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { bool success = false; bool value = getBoolValue(str.trimmed(), success); if (!success) return false; return setValue(value, reason); } bool QtnPropertyBoolBase::toStrImpl(QString &str) const { bool boolValue = value(); str = QtnPropertyBool::getBoolText(boolValue, true); return true; } QtnPropertyBool::QtnPropertyBool(QObject *parent) : QtnSinglePropertyValue(parent) { } QString QtnPropertyBool::getBoolText(bool value, bool internal) { static const char pFalse[] = QT_TRANSLATE_NOOP("QtnPropertyBool", "False"); static const char pTrue[] = QT_TRANSLATE_NOOP("QtnPropertyBool", "True"); if (internal) return QString(value ? pTrue : pFalse); return QCoreApplication::translate( "QtnPropertyBool", value ? pTrue : pFalse); } QtnPropertyBoolCallback::QtnPropertyBoolCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } ================================================ FILE: QtnProperty/Core/PropertyBool.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYBOOL_H #define PROPERTYBOOL_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" class QTN_IMPORT_EXPORT QtnPropertyBoolBase : public QtnSinglePropertyBase { Q_OBJECT private: QtnPropertyBoolBase(const QtnPropertyBoolBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyBoolBase(QObject *parent = nullptr); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyBoolBase) }; P_PROPERTY_DECL_ALL_OPERATORS(QtnPropertyBoolBase, bool) class QTN_IMPORT_EXPORT QtnPropertyBoolCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyBoolCallback( const QtnPropertyBoolCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyBoolCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyBoolCallback, QtnPropertyBoolBase) }; class QTN_IMPORT_EXPORT QtnPropertyBool : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyBool(const QtnPropertyBool &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyBool(QObject *parent = nullptr); static QString getBoolText(bool value, bool internal); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyBool, QtnPropertyBoolBase) }; #endif // PROPERTYBOOL_H ================================================ FILE: QtnProperty/Core/PropertyDouble.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDouble.h" QtnPropertyDoubleBase::QtnPropertyDoubleBase(QObject *parent) : QtnNumericPropertyBase>(parent) { } bool QtnPropertyDoubleBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { bool ok = false; ValueType value = str.toDouble(&ok); if (!ok) return false; return setValue(value, reason); } bool QtnPropertyDoubleBase::toStrImpl(QString &str) const { str = QString::number(value(), 'g', std::numeric_limits::digits10); return true; } QtnPropertyDoubleCallback::QtnPropertyDoubleCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } QtnPropertyDouble::QtnPropertyDouble(QObject *parent) : QtnNumericPropertyValue(parent) { } ================================================ FILE: QtnProperty/Core/PropertyDouble.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYDOUBLE_H #define PROPERTYDOUBLE_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" class QTN_IMPORT_EXPORT QtnPropertyDoubleBase : public QtnNumericPropertyBase> { Q_OBJECT private: QtnPropertyDoubleBase(const QtnPropertyDoubleBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyDoubleBase(QObject *parent); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyDoubleBase) }; P_PROPERTY_DECL_ALL_OPERATORS(QtnPropertyDoubleBase, double) class QTN_IMPORT_EXPORT QtnPropertyDoubleCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyDoubleCallback( const QtnPropertyDoubleCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyDoubleCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyDoubleCallback, QtnPropertyDoubleBase) }; class QTN_IMPORT_EXPORT QtnPropertyDouble : public QtnNumericPropertyValue { Q_OBJECT private: QtnPropertyDouble(const QtnPropertyDouble &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyDouble(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyDouble, QtnPropertyDoubleBase) }; #endif // PROPERTYDOUBLE_H ================================================ FILE: QtnProperty/Core/PropertyEnum.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyEnum.h" QtnPropertyEnumBase::QtnPropertyEnumBase(QObject *parent) : QtnSinglePropertyBase(parent) , m_enumInfo(nullptr) { } bool QtnPropertyEnumBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { if (!m_enumInfo) return false; const QtnEnumValueInfo *enumValue = m_enumInfo->fromStr(str); if (!enumValue) return false; return setValue(enumValue->value(), reason); } bool QtnPropertyEnumBase::toStrImpl(QString &str) const { if (!m_enumInfo) return false; QtnEnumValueType v = value(); const QtnEnumValueInfo *enumValue = m_enumInfo->findByValue(v); return m_enumInfo->toStr(str, enumValue); } bool QtnPropertyEnumBase::isValueAcceptedImpl(ValueType valueToAccept) { if (!m_enumInfo) return false; if (!m_enumInfo->findByValue(valueToAccept)) return false; return true; } QtnPropertyEnumCallback::QtnPropertyEnumCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } QtnPropertyEnum::QtnPropertyEnum(QObject *parent) : QtnSinglePropertyValue(parent) { } ================================================ FILE: QtnProperty/Core/PropertyEnum.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYENUM_H #define PROPERTYENUM_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include "QtnProperty/Enum.h" class QTN_IMPORT_EXPORT QtnPropertyEnumBase : public QtnSinglePropertyBase { Q_OBJECT private: QtnPropertyEnumBase(const QtnPropertyEnumBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyEnumBase(QObject *parent); inline const QtnEnumInfo *enumInfo() const; inline void setEnumInfo(const QtnEnumInfo *enumInfo); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; bool isValueAcceptedImpl(ValueType valueToAccept) override; private: const QtnEnumInfo *m_enumInfo; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyEnumBase) }; const QtnEnumInfo *QtnPropertyEnumBase::enumInfo() const { return m_enumInfo; } void QtnPropertyEnumBase::setEnumInfo(const QtnEnumInfo *enumInfo) { m_enumInfo = enumInfo; } P_PROPERTY_DECL_ALL_OPERATORS(QtnPropertyEnumBase, QtnEnumValueType) class QTN_IMPORT_EXPORT QtnPropertyEnumCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyEnumCallback( const QtnPropertyEnumCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyEnumCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyEnumCallback, QtnPropertyEnumBase) }; class QTN_IMPORT_EXPORT QtnPropertyEnum : public QtnSinglePropertyValue { Q_OBJECT QtnPropertyEnum(const QtnPropertyEnum &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyEnum(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyEnum, QtnPropertyEnumBase) }; #endif // PROPERTYENUM_H ================================================ FILE: QtnProperty/Core/PropertyEnumFlags.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyEnumFlags.h" QtnPropertyEnumFlagsBase::QtnPropertyEnumFlagsBase(QObject *parent) : QtnSinglePropertyBase(parent) , m_enumInfo(0) { } bool QtnPropertyEnumFlagsBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { if (!m_enumInfo) return false; QtnEnumFlagsValueType val = 0; QString enumStr = str.trimmed(); if (!enumStr.isEmpty() && enumStr != "0") { static QRegExp parserEnumFlags( QStringLiteral("^\\s*([^|\\s]+)\\s*\\|(.+)$"), Qt::CaseInsensitive); while (parserEnumFlags.exactMatch(enumStr)) { QStringList params = parserEnumFlags.capturedTexts(); if (params.size() != 3) return false; const QtnEnumValueInfo *enumValue = m_enumInfo->fromStr(params[1]); if (!enumValue) return false; val = val | enumValue->value(); enumStr = params[2]; } const QtnEnumValueInfo *enumValue = m_enumInfo->fromStr(enumStr); if (!enumValue) return false; val = val | enumValue->value(); } return setValue(val, reason); } bool QtnPropertyEnumFlagsBase::toStrImpl(QString &str) const { if (!m_enumInfo) return false; QtnEnumFlagsValueType v = value(); if (v == 0) { str = "0"; return true; } QString strValues; m_enumInfo->forEachEnumValue( [&strValues, v, this](const QtnEnumValueInfo &value) -> bool // { if (v & value.value()) { if (!strValues.isEmpty()) strValues += "|"; QString enumStr; m_enumInfo->toStr(enumStr, &value); strValues += enumStr; } return true; }); Q_ASSERT(!strValues.isEmpty()); str = strValues; return true; } QtnPropertyEnumFlags::QtnPropertyEnumFlags(QObject *parent) : QtnSinglePropertyValue(parent) { } QString QtnPropertyEnumFlags::getFlagLabelDescription( const QString &flagName, const QString &ownerName) { return tr("%1 flag for %2").arg(flagName, ownerName); } QtnPropertyEnumFlagsCallback::QtnPropertyEnumFlagsCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } ================================================ FILE: QtnProperty/Core/PropertyEnumFlags.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYENUMFLAGS_H #define PROPERTYENUMFLAGS_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include "QtnProperty/Enum.h" typedef qint32 QtnEnumFlagsValueType; class QTN_IMPORT_EXPORT QtnPropertyEnumFlagsBase : public QtnSinglePropertyBase { Q_OBJECT private: QtnPropertyEnumFlagsBase( const QtnPropertyEnumFlagsBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyEnumFlagsBase(QObject *parent); inline const QtnEnumInfo *enumInfo() const; inline void setEnumInfo(const QtnEnumInfo *enumInfo); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; private: const QtnEnumInfo *m_enumInfo; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyEnumFlagsBase) }; const QtnEnumInfo *QtnPropertyEnumFlagsBase::enumInfo() const { return m_enumInfo; } void QtnPropertyEnumFlagsBase::setEnumInfo(const QtnEnumInfo *enumInfo) { m_enumInfo = enumInfo; } P_PROPERTY_DECL_ALL_OPERATORS(QtnPropertyEnumFlagsBase, QtnEnumFlagsValueType) class QTN_IMPORT_EXPORT QtnPropertyEnumFlagsCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyEnumFlagsCallback( const QtnPropertyEnumFlagsCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyEnumFlagsCallback( QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyEnumFlagsCallback, QtnPropertyEnumFlagsBase) }; class QTN_IMPORT_EXPORT QtnPropertyEnumFlags : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyEnumFlags(const QtnPropertyEnumFlags &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyEnumFlags(QObject *parent = nullptr); static QString getFlagLabelDescription( const QString &flagName, const QString &ownerName); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyEnumFlags, QtnPropertyEnumFlagsBase) }; #endif // PROPERTYENUMFLAGS_H ================================================ FILE: QtnProperty/Core/PropertyFloat.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyFloat.h" QtnPropertyFloatBase::QtnPropertyFloatBase(QObject *parent) : QtnNumericPropertyBase>(parent) { } bool QtnPropertyFloatBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { bool ok = false; ValueType value = str.toFloat(&ok); if (!ok) return false; return setValue(value, reason); } bool QtnPropertyFloatBase::toStrImpl(QString &str) const { str = QString::number(value(), 'g', std::numeric_limits::digits10); return true; } QtnPropertyFloatCallback::QtnPropertyFloatCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } QtnPropertyFloat::QtnPropertyFloat(QObject *parent) : QtnNumericPropertyValue(parent) { } ================================================ FILE: QtnProperty/Core/PropertyFloat.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYFLOAT_H #define PROPERTYFLOAT_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" class QTN_IMPORT_EXPORT QtnPropertyFloatBase : public QtnNumericPropertyBase> { Q_OBJECT private: QtnPropertyFloatBase(const QtnPropertyFloatBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyFloatBase(QObject *parent); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyFloatBase) }; P_PROPERTY_DECL_ALL_OPERATORS(QtnPropertyFloatBase, float) class QTN_IMPORT_EXPORT QtnPropertyFloatCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyFloatCallback( const QtnPropertyFloatCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyFloatCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyFloatCallback, QtnPropertyFloatBase) }; class QTN_IMPORT_EXPORT QtnPropertyFloat : public QtnNumericPropertyValue { Q_OBJECT private: QtnPropertyFloat(const QtnPropertyFloat &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyFloat(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyFloat, QtnPropertyFloatBase) }; #endif // PROPERTYFLOAT_H ================================================ FILE: QtnProperty/Core/PropertyInt.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyInt.h" #include QtnPropertyIntBase::QtnPropertyIntBase(QObject *parent) : QtnNumericPropertyBase>(parent) { } bool QtnPropertyIntBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { bool ok = false; ValueType value = str.toInt(&ok); if (!ok) return false; return setValue(value, reason); } bool QtnPropertyIntBase::toStrImpl(QString &str) const { str = QString::number(value()); return true; } QtnPropertyIntCallback::QtnPropertyIntCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } QtnPropertyInt::QtnPropertyInt(QObject *parent) : QtnNumericPropertyValue(parent) { } ================================================ FILE: QtnProperty/Core/PropertyInt.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYINT_H #define PROPERTYINT_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" class QTN_IMPORT_EXPORT QtnPropertyIntBase : public QtnNumericPropertyBase> { Q_OBJECT private: QtnPropertyIntBase(const QtnPropertyIntBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyIntBase(QObject *parent); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyIntBase) }; P_PROPERTY_DECL_ALL_OPERATORS(QtnPropertyIntBase, qint32) class QTN_IMPORT_EXPORT QtnPropertyIntCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyIntCallback( const QtnPropertyIntCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyIntCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyIntCallback, QtnPropertyIntBase) }; class QTN_IMPORT_EXPORT QtnPropertyInt : public QtnNumericPropertyValue { Q_OBJECT private: QtnPropertyInt(const QtnPropertyInt &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyInt(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyInt, QtnPropertyIntBase) }; #endif // PROPERTYINT_H ================================================ FILE: QtnProperty/Core/PropertyQPoint.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQPoint.h" QtnPropertyQPointBase::QtnPropertyQPointBase(QObject *parent) : ParentClass(parent) { } QtnProperty *QtnPropertyQPointBase::createXProperty() { return createFieldProperty(&QPoint::x, &QPoint::setX, QtnPropertyQPoint::xKey(), QtnPropertyQPoint::xDisplayName(), QtnPropertyQPoint::xDescriptionFmt()); } QtnProperty *QtnPropertyQPointBase::createYProperty() { return createFieldProperty(&QPoint::y, &QPoint::setY, QtnPropertyQPoint::yKey(), QtnPropertyQPoint::yDisplayName(), QtnPropertyQPoint::yDescriptionFmt()); } bool QtnPropertyQPointBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { static QRegExp parserPoint( "^\\s*QPoint\\s*\\(([^\\)]+)\\)\\s*$", Qt::CaseInsensitive); if (!parserPoint.exactMatch(str)) return false; QStringList params = parserPoint.capturedTexts(); if (params.size() != 2) return false; static QRegExp parserParams( "^\\s*(-?\\d+)\\s*,\\s*(-?\\d+)\\s*$", Qt::CaseInsensitive); if (!parserParams.exactMatch(params[1])) return false; params = parserParams.capturedTexts(); if (params.size() != 3) return false; bool ok = false; int x = params[1].toInt(&ok); if (!ok) return false; int y = params[2].toInt(&ok); if (!ok) return false; return setValue(QPoint(x, y), reason); } bool QtnPropertyQPointBase::toStrImpl(QString &str) const { QPoint v = value(); str = QStringLiteral("QPoint(%1, %2)").arg(v.x()).arg(v.y()); return true; } QtnPropertyQPoint::QtnPropertyQPoint(QObject *parent) : QtnSinglePropertyValue(parent) { } QString QtnPropertyQPoint::getToStringFormat() { return tr("[%1, %2]"); } QString QtnPropertyQPoint::xKey() { return QStringLiteral("x"); } QString QtnPropertyQPoint::xDisplayName() { return tr("X"); } QString QtnPropertyQPoint::xDescriptionFmt() { return tr("X of the %1"); } QString QtnPropertyQPoint::yKey() { return QStringLiteral("y"); } QString QtnPropertyQPoint::yDisplayName() { return tr("Y"); } QString QtnPropertyQPoint::yDescriptionFmt() { return tr("Y of the %1"); } QtnPropertyQPointCallback::QtnPropertyQPointCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } ================================================ FILE: QtnProperty/Core/PropertyQPoint.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYQPOINT_H #define PROPERTYQPOINT_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include "PropertyInt.h" #include "QtnProperty/StructPropertyBase.h" #include class QTN_IMPORT_EXPORT QtnPropertyQPointBase : public QtnStructPropertyBase { Q_OBJECT private: QtnPropertyQPointBase(const QtnPropertyQPointBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQPointBase(QObject *parent); QtnProperty *createXProperty(); QtnProperty *createYProperty(); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyQPointBase) }; P_PROPERTY_DECL_EQ_OPERATORS(QtnPropertyQPointBase, QPoint) class QTN_IMPORT_EXPORT QtnPropertyQPointCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyQPointCallback( const QtnPropertyQPointCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQPointCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQPointCallback, QtnPropertyQPointBase) }; class QTN_IMPORT_EXPORT QtnPropertyQPoint : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyQPoint(const QtnPropertyQPoint &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQPoint(QObject *parent = nullptr); static QString getToStringFormat(); static QString xKey(); static QString xDisplayName(); static QString xDescriptionFmt(); static QString yKey(); static QString yDisplayName(); static QString yDescriptionFmt(); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyQPoint, QtnPropertyQPointBase) }; #endif // PROPERTYQPOINT_H ================================================ FILE: QtnProperty/Core/PropertyQPointF.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQPointF.h" #include "PropertyQPoint.h" QtnPropertyQPointFBase::QtnPropertyQPointFBase(QObject *parent) : ParentClass(parent) { } QtnProperty *QtnPropertyQPointFBase::createXProperty() { return createFieldProperty(&QPointF::x, &QPointF::setX, QtnPropertyQPoint::xKey(), getXLabel(), getXDescriptionFormat()); } QtnProperty *QtnPropertyQPointFBase::createYProperty() { return createFieldProperty(&QPointF::y, &QPointF::setY, QtnPropertyQPoint::yKey(), getYLabel(), getYDescriptionFormat()); } QString QtnPropertyQPointFBase::getXLabel() const { return QtnPropertyQPoint::xDisplayName(); } QString QtnPropertyQPointFBase::getXDescriptionFormat() const { return QtnPropertyQPoint::xDescriptionFmt(); } QString QtnPropertyQPointFBase::getYLabel() const { return QtnPropertyQPoint::yDisplayName(); } QString QtnPropertyQPointFBase::getYDescriptionFormat() const { return QtnPropertyQPoint::yDescriptionFmt(); } bool QtnPropertyQPointFBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { static QRegExp parserPoint( QLatin1String("^\\s*QPointF\\s*\\(([^\\)]+)\\)\\s*$"), Qt::CaseInsensitive); if (!parserPoint.exactMatch(str)) return false; QStringList params = parserPoint.capturedTexts(); if (params.size() != 2) return false; static QRegExp parserParams( "^\\s*(\\-?\\d+(\\.\\d{0,})?)\\s*,\\s*(\\-?\\d+(\\.\\d{0,})?)\\s*$", Qt::CaseInsensitive); if (!parserParams.exactMatch(params[1])) return false; params = parserParams.capturedTexts(); if (params.size() != 5) return false; bool ok = false; double x = params[1].toDouble(&ok); if (!ok) return false; double y = params[3].toDouble(&ok); if (!ok) return false; return setValue(QPointF(x, y), reason); } bool QtnPropertyQPointFBase::toStrImpl(QString &str) const { QPointF v = value(); str = QStringLiteral("QPointF(%1, %2)").arg(v.x()).arg(v.y()); return true; } QtnPropertyQPointF::QtnPropertyQPointF(QObject *parent) : QtnSinglePropertyValue(parent) { } QtnPropertyQPointFCallback::QtnPropertyQPointFCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } ================================================ FILE: QtnProperty/Core/PropertyQPointF.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYQPOINTF_H #define PROPERTYQPOINTF_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include "PropertyDouble.h" #include "QtnProperty/StructPropertyBase.h" #include class QTN_IMPORT_EXPORT QtnPropertyQPointFBase : public QtnStructPropertyBase { Q_OBJECT private: QtnPropertyQPointFBase( const QtnPropertyQPointFBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQPointFBase(QObject *parent); QtnProperty *createXProperty(); QtnProperty *createYProperty(); virtual QString getXLabel() const; virtual QString getXDescriptionFormat() const; virtual QString getYLabel() const; virtual QString getYDescriptionFormat() const; protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyQPointFBase) }; P_PROPERTY_DECL_EQ_OPERATORS(QtnPropertyQPointFBase, QPointF) class QTN_IMPORT_EXPORT QtnPropertyQPointFCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyQPointFCallback( const QtnPropertyQPointFCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQPointFCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQPointFCallback, QtnPropertyQPointFBase) }; class QTN_IMPORT_EXPORT QtnPropertyQPointF : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyQPointF(const QtnPropertyQPointF &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQPointF(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQPointF, QtnPropertyQPointFBase) }; #endif // PROPERTYQPOINTF_H ================================================ FILE: QtnProperty/Core/PropertyQRect.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQRect.h" #include "PropertyQSize.h" QtnProperty *QtnPropertyQRectBase::createLeftProperty(bool move) { return createFieldProperty(&QRect::left, move ? &QRect::moveLeft : &QRect::setLeft, QtnPropertyQRect::leftKey(), QtnPropertyQRect::leftString(), QtnPropertyQRect::leftDescriptionFmt()); } QtnProperty *QtnPropertyQRectBase::createTopProperty(bool move) { return createFieldProperty(&QRect::top, move ? &QRect::moveTop : &QRect::setTop, QtnPropertyQRect::topKey(), QtnPropertyQRect::topString(), QtnPropertyQRect::topDescriptionFmt()); } QtnProperty *QtnPropertyQRectBase::createRightProperty(bool move) { return createFieldProperty(&QRect::right, move ? &QRect::moveRight : &QRect::setRight, QtnPropertyQRect::rightKey(), QtnPropertyQRect::rightString(), QtnPropertyQRect::rightDescriptionFmt()); } QtnProperty *QtnPropertyQRectBase::createBottomProperty(bool move) { return createFieldProperty(&QRect::bottom, move ? &QRect::moveBottom : &QRect::setBottom, QtnPropertyQRect::bottomKey(), QtnPropertyQRect::bottomString(), QtnPropertyQRect::bottomDescriptionFmt()); } QtnProperty *QtnPropertyQRectBase::createWidthProperty() { return createFieldProperty(&QRect::width, &QRect::setWidth, QtnPropertyQSize::widthKey(), QtnPropertyQSize::widthDisplayName(), QtnPropertyQSize::widthDescriptionFmt()); } QtnProperty *QtnPropertyQRectBase::createHeightProperty() { return createFieldProperty(&QRect::height, &QRect::setHeight, QtnPropertyQSize::heightKey(), QtnPropertyQSize::heightDisplayName(), QtnPropertyQSize::heightDescriptionFmt()); } QByteArray QtnPropertyQRect::delegateName(bool coordinateMode) { if (coordinateMode) { return QByteArrayLiteral("LTRB"); } else { return QByteArrayLiteral("LTWH"); } } QtnPropertyQRectBase::QtnPropertyQRectBase(QObject *parent) : ParentClass(parent) { } bool QtnPropertyQRectBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { static QRegExp parserRect( "^\\s*QRect\\s*\\(([^\\)]+)\\)\\s*$", Qt::CaseInsensitive); static QRegExp parserParams( "^\\s*(-?\\d+)\\s*,\\s*(-?\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*$", Qt::CaseInsensitive); if (!parserRect.exactMatch(str)) return false; QStringList params = parserRect.capturedTexts(); if (params.size() != 2) return false; if (!parserParams.exactMatch(params[1])) return false; params = parserParams.capturedTexts(); if (params.size() != 5) return false; bool ok = false; int left = params[1].toInt(&ok); if (!ok) return false; int top = params[2].toInt(&ok); if (!ok) return false; int width = params[3].toInt(&ok); if (!ok) return false; int height = params[4].toInt(&ok); if (!ok) return false; return setValue(QRect(left, top, width, height), reason); } bool QtnPropertyQRectBase::toStrImpl(QString &str) const { auto v = value(); str = QStringLiteral("QRect(%1, %2, %3, %4)") .arg(v.left()) .arg(v.top()) .arg(v.width()) .arg(v.height()); return true; } QtnPropertyQRect::QtnPropertyQRect(QObject *parent) : QtnSinglePropertyValue(parent) { } QString QtnPropertyQRect::getToStringFormat(bool coordinates) { return coordinates ? tr("[(%1, %2), (%3, %4)]") : tr("[(%1, %2) %3 x %4]"); } QString QtnPropertyQRect::leftKey() { return QStringLiteral("left"); } QString QtnPropertyQRect::leftString() { return tr("Left"); } QString QtnPropertyQRect::leftDescriptionFmt() { return tr("Left position of the %1"); } QString QtnPropertyQRect::topKey() { return QStringLiteral("top"); } QString QtnPropertyQRect::topString() { return tr("Top"); } QString QtnPropertyQRect::topDescriptionFmt() { return tr("Top position of the %1"); } QString QtnPropertyQRect::rightKey() { return QStringLiteral("right"); } QString QtnPropertyQRect::rightString() { return tr("Right"); } QString QtnPropertyQRect::rightDescriptionFmt() { return tr("Right position of the %1"); } QString QtnPropertyQRect::bottomKey() { return QStringLiteral("bottom"); } QString QtnPropertyQRect::bottomString() { return tr("Bottom"); } QString QtnPropertyQRect::bottomDescriptionFmt() { return tr("Bottom position of the %1"); } QtnPropertyQRectCallback::QtnPropertyQRectCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } ================================================ FILE: QtnProperty/Core/PropertyQRect.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYQRECT_H #define PROPERTYQRECT_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include "PropertyInt.h" #include "QtnProperty/StructPropertyBase.h" #include class QTN_IMPORT_EXPORT QtnPropertyQRectBase : public QtnStructPropertyBase { Q_OBJECT private: QtnPropertyQRectBase(const QtnPropertyQRectBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQRectBase(QObject *parent); QtnProperty *createLeftProperty(bool move); QtnProperty *createTopProperty(bool move); QtnProperty *createRightProperty(bool move); QtnProperty *createBottomProperty(bool move); QtnProperty *createWidthProperty(); QtnProperty *createHeightProperty(); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyQRectBase) }; P_PROPERTY_DECL_EQ_OPERATORS(QtnPropertyQRectBase, QRect) class QTN_IMPORT_EXPORT QtnPropertyQRectCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyQRectCallback( const QtnPropertyQRectCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQRectCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQRectCallback, QtnPropertyQRectBase) }; class QTN_IMPORT_EXPORT QtnPropertyQRect : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyQRect(const QtnPropertyQRect &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQRect(QObject *parent = nullptr); static QByteArray delegateName(bool coordinateMode); static QString getToStringFormat(bool m_coordinates); static QString leftKey(); static QString leftString(); static QString leftDescriptionFmt(); static QString topKey(); static QString topString(); static QString topDescriptionFmt(); static QString rightKey(); static QString rightString(); static QString rightDescriptionFmt(); static QString bottomKey(); static QString bottomString(); static QString bottomDescriptionFmt(); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyQRect, QtnPropertyQRectBase) }; #endif // PROPERTYQRECT_H ================================================ FILE: QtnProperty/Core/PropertyQRectF.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQRectF.h" #include "PropertyQRect.h" #include "PropertyQSize.h" QtnProperty *QtnPropertyQRectFBase::createLeftProperty(bool move) { return createFieldProperty(&QRectF::left, move ? &QRectF::moveLeft : &QRectF::setLeft, QtnPropertyQRect::leftKey(), QtnPropertyQRect::leftString(), QtnPropertyQRect::leftDescriptionFmt()); } QtnProperty *QtnPropertyQRectFBase::createTopProperty(bool move) { return createFieldProperty(&QRectF::top, move ? &QRectF::moveTop : &QRectF::setTop, QtnPropertyQRect::topKey(), QtnPropertyQRect::topString(), QtnPropertyQRect::topDescriptionFmt()); } QtnProperty *QtnPropertyQRectFBase::createRightProperty(bool move) { return createFieldProperty(&QRectF::right, move ? &QRectF::moveRight : &QRectF::setRight, QtnPropertyQRect::rightKey(), QtnPropertyQRect::rightString(), QtnPropertyQRect::rightDescriptionFmt()); } QtnProperty *QtnPropertyQRectFBase::createBottomProperty(bool move) { return createFieldProperty(&QRectF::bottom, move ? &QRectF::moveBottom : &QRectF::setBottom, QtnPropertyQRect::bottomKey(), QtnPropertyQRect::bottomString(), QtnPropertyQRect::bottomDescriptionFmt()); } QtnProperty *QtnPropertyQRectFBase::createWidthProperty() { return createFieldProperty(&QRectF::width, &QRectF::setWidth, QtnPropertyQSize::widthKey(), QtnPropertyQSize::widthDisplayName(), QtnPropertyQSize::widthDescriptionFmt()); } QtnProperty *QtnPropertyQRectFBase::createHeightProperty() { return createFieldProperty(&QRectF::height, &QRectF::setHeight, QtnPropertyQSize::heightKey(), QtnPropertyQSize::heightDisplayName(), QtnPropertyQSize::heightDescriptionFmt()); } QtnPropertyQRectFBase::QtnPropertyQRectFBase(QObject *parent) : ParentClass(parent) { } bool QtnPropertyQRectFBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { static QRegExp parserRect( "^\\s*QRectF\\s*\\(([^\\)]+)\\)\\s*$", Qt::CaseInsensitive); static QRegExp parserParams("^\\s*(\\-?\\d+(\\.\\d{0,})?)\\s*,\\s*(\\-?\\d+" "(\\.\\d{0,})?)\\s*,\\s*(\\d+(\\.\\d{0,})?)\\s*" ",\\s*(\\d+(\\.\\d{0,})?)\\s*$", Qt::CaseInsensitive); if (!parserRect.exactMatch(str)) return false; QStringList params = parserRect.capturedTexts(); if (params.size() != 2) return false; if (!parserParams.exactMatch(params[1])) return false; params = parserParams.capturedTexts(); if (params.size() != 9) return false; bool ok = false; double left = params[1].toDouble(&ok); if (!ok) return false; double top = params[3].toDouble(&ok); if (!ok) return false; double width = params[5].toDouble(&ok); if (!ok) return false; double height = params[7].toDouble(&ok); if (!ok) return false; return setValue(QRectF(left, top, width, height), reason); } bool QtnPropertyQRectFBase::toStrImpl(QString &str) const { auto v = value(); str = QStringLiteral("QRectF(%1, %2, %3, %4)") .arg(v.left()) .arg(v.top()) .arg(v.width()) .arg(v.height()); return true; } QtnPropertyQRectF::QtnPropertyQRectF(QObject *parent) : QtnSinglePropertyValue(parent) { } QtnPropertyQRectFCallback::QtnPropertyQRectFCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } ================================================ FILE: QtnProperty/Core/PropertyQRectF.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYQRECTF_H #define PROPERTYQRECTF_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include "PropertyDouble.h" #include "QtnProperty/StructPropertyBase.h" #include class QTN_IMPORT_EXPORT QtnPropertyQRectFBase : public QtnStructPropertyBase { Q_OBJECT private: QtnPropertyQRectFBase(const QtnPropertyQRectFBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQRectFBase(QObject *parent); QtnProperty *createLeftProperty(bool move); QtnProperty *createTopProperty(bool move); QtnProperty *createRightProperty(bool move); QtnProperty *createBottomProperty(bool move); QtnProperty *createWidthProperty(); QtnProperty *createHeightProperty(); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyQRectFBase) }; P_PROPERTY_DECL_EQ_OPERATORS(QtnPropertyQRectFBase, QRectF) class QTN_IMPORT_EXPORT QtnPropertyQRectFCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyQRectFCallback( const QtnPropertyQRectFCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQRectFCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQRectFCallback, QtnPropertyQRectFBase) }; class QTN_IMPORT_EXPORT QtnPropertyQRectF : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyQRectF(const QtnPropertyQRectF &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQRectF(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyQRectF, QtnPropertyQRectFBase) }; #endif // PROPERTYQRECT_H ================================================ FILE: QtnProperty/Core/PropertyQSize.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQSize.h" #include "PropertyInt.h" QtnPropertyQSizeBase::QtnPropertyQSizeBase(QObject *parent) : ParentClass(parent) { } QtnProperty *QtnPropertyQSizeBase::createWidthProperty() { return createFieldProperty(&QSize::width, &QSize::setWidth, QtnPropertyQSize::widthKey(), QtnPropertyQSize::widthDisplayName(), QtnPropertyQSize::widthDescriptionFmt()); } QtnProperty *QtnPropertyQSizeBase::createHeightProperty() { return createFieldProperty(&QSize::height, &QSize::setHeight, QtnPropertyQSize::heightKey(), QtnPropertyQSize::heightDisplayName(), QtnPropertyQSize::heightDescriptionFmt()); } bool QtnPropertyQSizeBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { static QRegExp parserSize( "^\\s*QSize\\s*\\(([^\\)]+)\\)\\s*$", Qt::CaseInsensitive); if (!parserSize.exactMatch(str)) return false; QStringList params = parserSize.capturedTexts(); if (params.size() != 2) return false; static QRegExp parserParams( "^\\s*(-?\\d+)\\s*,\\s*(-?\\d+)\\s*$", Qt::CaseInsensitive); if (!parserParams.exactMatch(params[1])) return false; params = parserParams.capturedTexts(); if (params.size() != 3) return false; bool ok = false; int width = params[1].toInt(&ok); if (!ok) return false; int height = params[2].toInt(&ok); if (!ok) return false; return setValue(QSize(width, height), reason); } bool QtnPropertyQSizeBase::toStrImpl(QString &str) const { QSize v = value(); str = QString("QSize(%1, %2)").arg(v.width()).arg(v.height()); return true; } QtnPropertyQSize::QtnPropertyQSize(QObject *parent) : QtnSinglePropertyValue(parent) { } QString QtnPropertyQSize::getToStringFormat() { return tr("[%1 x %2]"); } QString QtnPropertyQSize::widthKey() { return QStringLiteral("width"); } QString QtnPropertyQSize::widthDisplayName() { return tr("Width"); } QString QtnPropertyQSize::widthDescriptionFmt() { return tr("Width of the %1"); } QString QtnPropertyQSize::heightKey() { return QStringLiteral("height"); } QString QtnPropertyQSize::heightDisplayName() { return tr("Height"); } QString QtnPropertyQSize::heightDescriptionFmt() { return tr("Height of the %1"); } QtnPropertyQSizeCallback::QtnPropertyQSizeCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } ================================================ FILE: QtnProperty/Core/PropertyQSize.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYQSIZE_H #define PROPERTYQSIZE_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include "PropertyInt.h" #include "QtnProperty/StructPropertyBase.h" #include class QTN_IMPORT_EXPORT QtnPropertyQSizeBase : public QtnStructPropertyBase { Q_OBJECT private: QtnPropertyQSizeBase(const QtnPropertyQSizeBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQSizeBase(QObject *parent); QtnProperty *createWidthProperty(); QtnProperty *createHeightProperty(); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyQSizeBase) }; P_PROPERTY_DECL_EQ_OPERATORS(QtnPropertyQSizeBase, QSize) class QTN_IMPORT_EXPORT QtnPropertyQSizeCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyQSizeCallback( const QtnPropertyQSizeCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQSizeCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQSizeCallback, QtnPropertyQSizeBase) }; class QTN_IMPORT_EXPORT QtnPropertyQSize : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyQSize(const QtnPropertyQSize &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQSize(QObject *parent = nullptr); static QString getToStringFormat(); static QString widthKey(); static QString widthDisplayName(); static QString widthDescriptionFmt(); static QString heightKey(); static QString heightDisplayName(); static QString heightDescriptionFmt(); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyQSize, QtnPropertyQSizeBase) }; #endif // PROPERTYQSIZE_H ================================================ FILE: QtnProperty/Core/PropertyQSizeF.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQSizeF.h" #include "PropertyQSize.h" QtnPropertyQSizeFBase::QtnPropertyQSizeFBase(QObject *parent) : ParentClass(parent) { } QtnProperty *QtnPropertyQSizeFBase::createWidthProperty() { return createFieldProperty(&QSizeF::width, &QSizeF::setWidth, QtnPropertyQSize::widthKey(), QtnPropertyQSize::widthDisplayName(), QtnPropertyQSize::widthDescriptionFmt()); } QtnProperty *QtnPropertyQSizeFBase::createHeightProperty() { return createFieldProperty(&QSizeF::height, &QSizeF::setHeight, QtnPropertyQSize::heightKey(), QtnPropertyQSize::heightDisplayName(), QtnPropertyQSize::heightDescriptionFmt()); } bool QtnPropertyQSizeFBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { static QRegExp parserSize( "^\\s*QSizeF\\s*\\(([^\\)]+)\\)\\s*$", Qt::CaseInsensitive); if (!parserSize.exactMatch(str)) return false; QStringList params = parserSize.capturedTexts(); if (params.size() != 2) return false; static QRegExp parserParams( "^\\s*(\\-?\\d+(\\.\\d{0,})?)\\s*,\\s*(\\-?\\d+(\\.\\d{0,})?)\\s*$", Qt::CaseInsensitive); if (!parserParams.exactMatch(params[1])) return false; params = parserParams.capturedTexts(); if (params.size() != 5) return false; bool ok = false; double width = params[1].toDouble(&ok); if (!ok) return false; double height = params[3].toDouble(&ok); if (!ok) return false; return setValue(QSizeF(width, height), reason); } bool QtnPropertyQSizeFBase::toStrImpl(QString &str) const { QSizeF v = value(); str = QString("QSizeF(%1, %2)").arg(v.width()).arg(v.height()); return true; } QtnPropertyQSizeF::QtnPropertyQSizeF(QObject *parent) : QtnSinglePropertyValue(parent) { } QtnPropertyQSizeFCallback::QtnPropertyQSizeFCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } ================================================ FILE: QtnProperty/Core/PropertyQSizeF.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYQSIZEF_H #define PROPERTYQSIZEF_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include "PropertyDouble.h" #include "QtnProperty/StructPropertyBase.h" #include class QTN_IMPORT_EXPORT QtnPropertyQSizeFBase : public QtnStructPropertyBase { Q_OBJECT private: QtnPropertyQSizeFBase(const QtnPropertyQSizeFBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQSizeFBase(QObject *parent); QtnProperty *createWidthProperty(); QtnProperty *createHeightProperty(); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyQSizeFBase) }; P_PROPERTY_DECL_EQ_OPERATORS(QtnPropertyQSizeFBase, QSizeF) class QTN_IMPORT_EXPORT QtnPropertyQSizeFCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyQSizeFCallback( const QtnPropertyQSizeFCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQSizeFCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQSizeFCallback, QtnPropertyQSizeFBase) }; class QTN_IMPORT_EXPORT QtnPropertyQSizeF : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyQSizeF(const QtnPropertyQSizeF &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQSizeF(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyQSizeF, QtnPropertyQSizeFBase) }; #endif // PROPERTYQSIZEF_H ================================================ FILE: QtnProperty/Core/PropertyQString.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQString.h" QtnPropertyQStringBase::QtnPropertyQStringBase(QObject *parent) : QtnSinglePropertyBase(parent) { } QtnPropertyQStringBase &QtnPropertyQStringBase::operator=(const char *newValue) { setValue(QString(newValue)); return *this; } bool QtnPropertyQStringBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { return setValue(str, reason); } bool QtnPropertyQStringBase::toStrImpl(QString &str) const { str = value(); return true; } QtnPropertyQString::QtnPropertyQString(QObject *parent) : QtnSinglePropertyValue(parent) { } QtnPropertyQString &QtnPropertyQString::operator=(const char *newValue) { setValue(QString(newValue)); return *this; } bool QtnPropertyQString::isMultilineText(const QString &text) { return text.contains('\n') || text.contains('\r'); } QString QtnPropertyQString::getEmptyPlaceholderStr() { return tr("(Empty)"); } QString QtnPropertyQString::getPlaceholderStr( const QString &text, bool checkMultiline) { if (checkMultiline && isMultilineText(text)) return tr("(Multiline Text)"); if (text.isEmpty()) return getEmptyPlaceholderStr(); return QString(); } QString QtnPropertyQString::getReadOnlyPropertyTitleFormat() { return tr("%1 (Read only)"); } QtnPropertyQStringCallback::QtnPropertyQStringCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } QtnPropertyQStringCallback &QtnPropertyQStringCallback::operator=( const char *newValue) { setValue(QString(newValue)); return *this; } ================================================ FILE: QtnProperty/Core/PropertyQString.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYSTRING_H #define PROPERTYSTRING_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" class QTN_IMPORT_EXPORT QtnPropertyQStringBase : public QtnSinglePropertyBase { Q_OBJECT private: QtnPropertyQStringBase( const QtnPropertyQStringBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQStringBase(QObject *parent); QtnPropertyQStringBase &operator=(const char *newValue); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyQStringBase) }; P_PROPERTY_DECL_ALL_OPERATORS(QtnPropertyQStringBase, QString) class QTN_IMPORT_EXPORT QtnPropertyQStringCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyQStringCallback( const QtnPropertyQStringCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQStringCallback(QObject *parent = nullptr); QtnPropertyQStringCallback &operator=(const char *newValue); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQStringCallback, QtnPropertyQStringBase) }; class QTN_IMPORT_EXPORT QtnPropertyQString : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyQString(const QtnPropertyQString &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQString(QObject *parent = nullptr); QtnPropertyQString &operator=(const char *newValue); static bool isMultilineText(const QString &text); static QString getEmptyPlaceholderStr(); static QString getPlaceholderStr(const QString &text, bool checkMultiline); static QString getReadOnlyPropertyTitleFormat(); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQString, QtnPropertyQStringBase) }; #endif // PROPERTYSTRING_H ================================================ FILE: QtnProperty/Core/PropertyUInt.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyUInt.h" #include QtnPropertyUIntBase::QtnPropertyUIntBase(QObject *parent) : QtnNumericPropertyBase>(parent) { } bool QtnPropertyUIntBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { bool ok = false; ValueType value = str.toUInt(&ok); if (!ok) return false; return setValue(value, reason); } bool QtnPropertyUIntBase::toStrImpl(QString &str) const { str = QString::number(value()); return true; } QtnPropertyUIntCallback::QtnPropertyUIntCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } QtnPropertyUInt::QtnPropertyUInt(QObject *parent) : QtnNumericPropertyValue(parent) { } ================================================ FILE: QtnProperty/Core/PropertyUInt.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYUINT_H #define PROPERTYUINT_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" class QTN_IMPORT_EXPORT QtnPropertyUIntBase : public QtnNumericPropertyBase> { Q_OBJECT private: QtnPropertyUIntBase(const QtnPropertyUIntBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyUIntBase(QObject *parent); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyUIntBase) }; P_PROPERTY_DECL_ALL_OPERATORS(QtnPropertyUIntBase, quint32) class QTN_IMPORT_EXPORT QtnPropertyUIntCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyUIntCallback( const QtnPropertyUIntCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyUIntCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyUIntCallback, QtnPropertyUIntBase) }; class QTN_IMPORT_EXPORT QtnPropertyUInt : public QtnNumericPropertyValue { Q_OBJECT private: QtnPropertyUInt(const QtnPropertyUInt &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyUInt(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyUInt, QtnPropertyUIntBase) }; #endif // PROPERTYUINT_H ================================================ FILE: QtnProperty/CustomPropertyEditorDialog.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "CustomPropertyEditorDialog.h" #include "ui_CustomPropertyEditorDialog.h" #include "Utils/InplaceEditing.h" #include "PropertyView.h" #include "VarProperty.h" #include #include CustomPropertyEditorDialog::CustomPropertyEditorDialog(QWidget *parent) : QDialog(parent) , ui(new Ui::CustomPropertyEditorDialog) { ui->setupUi(this); updateTitle(); setWindowFlags((windowFlags() & ~(Qt::WindowContextHelpButtonHint)) | Qt::WindowCloseButtonHint | Qt::WindowMaximizeButtonHint); QObject::connect(ui->propertyWidget->propertyView(), &QtnPropertyView::activePropertyChanged, this, &CustomPropertyEditorDialog::onActivePropertyChanged); #ifdef Q_OS_MAC QtnPropertyWidgetEx::addShortcutForAction(QKeySequence(Qt::Key_Backspace), ui->actionPropertyDelete, this, Qt::WindowShortcut); #endif QtnPropertyWidgetEx::addShortcutForAction(QKeySequence(Qt::Key_Delete), ui->actionPropertyDelete, this, Qt::WindowShortcut); #ifdef Q_OS_WIN QtnPropertyWidgetEx::addShortcutForAction( QKeySequence(Qt::CTRL | Qt::Key_Insert), ui->actionPropertyCopy, this, Qt::WindowShortcut); QtnPropertyWidgetEx::addShortcutForAction( QKeySequence(Qt::SHIFT | Qt::Key_Insert), ui->actionPropertyPaste, this, Qt::WindowShortcut); #endif QtnPropertyWidgetEx::addShortcutForAction(ui->actionPropertyCut->shortcut(), ui->actionPropertyCut, this, Qt::WindowShortcut); QtnPropertyWidgetEx::addShortcutForAction( ui->actionPropertyCopy->shortcut(), ui->actionPropertyCopy, this, Qt::WindowShortcut); QtnPropertyWidgetEx::addShortcutForAction( ui->actionPropertyPaste->shortcut(), ui->actionPropertyPaste, this, Qt::WindowShortcut); QtnPropertyWidgetEx::addShortcutForAction( ui->actionPropertyOptions->shortcut(), ui->actionPropertyOptions, this, Qt::WindowShortcut); QtnPropertyWidgetEx::addShortcutForAction(ui->actionPropertyAdd->shortcut(), ui->actionPropertyAdd, this, Qt::WindowShortcut); ui->propertyWidget->connectDeleteAction(ui->actionPropertyDelete, true); ui->propertyWidget->connectCutAction(ui->actionPropertyCut, true); ui->propertyWidget->connectCopyAction(ui->actionPropertyCopy, true); ui->propertyWidget->connectPasteAction(ui->actionPropertyPaste, true); } CustomPropertyEditorDialog::~CustomPropertyEditorDialog() { delete ui; } bool CustomPropertyEditorDialog::execute(const QString &title, QVariant &data) { ui->propertyWidget->setData(&data, title); updateActions(); show(); raise(); exec(); if (result() == Accepted) { ui->propertyWidget->updateData(); return true; } return false; } void CustomPropertyEditorDialog::setReadOnly(bool value) { ui->propertyWidget->setReadOnly(value); updateTitle(); if (value) { ui->buttonBox->setStandardButtons(QDialogButtonBox::Close); } else { ui->buttonBox->setStandardButtons( QDialogButtonBox::Ok | QDialogButtonBox::Cancel); } } void CustomPropertyEditorDialog::accept() { qtnStopInplaceEdit(false); QDialog::accept(); } void CustomPropertyEditorDialog::reject() { qtnStopInplaceEdit(false); QDialog::reject(); } void CustomPropertyEditorDialog::onActivePropertyChanged( QtnPropertyBase *activeProperty) { updateActions(activeProperty); } void CustomPropertyEditorDialog::on_buttonBox_clicked(QAbstractButton *button) { switch (ui->buttonBox->buttonRole(button)) { case QDialogButtonBox::AcceptRole: accept(); break; case QDialogButtonBox::RejectRole: reject(); break; default: break; } } void CustomPropertyEditorDialog::on_propertyWidget_customContextMenuRequested( const QPoint &pos) { auto property = ui->propertyWidget->propertyView()->activeProperty(); if (nullptr != property) { qtnStopInplaceEdit(false); QMenu menu(this); menu.addAction(ui->actionPropertyOptions); menu.addSeparator(); menu.addAction(ui->actionPropertyAdd); menu.addAction(ui->actionPropertyDuplicate); menu.addSeparator(); menu.addAction(ui->actionPropertyCut); menu.addAction(ui->actionPropertyCopy); menu.addAction(ui->actionPropertyPaste); menu.addSeparator(); menu.addAction(ui->actionPropertyDelete); updateActions(property); menu.exec(ui->propertyWidget->mapToGlobal(pos)); } } void CustomPropertyEditorDialog::on_actionPropertyAdd_triggered() { ui->propertyWidget->addProperty(); } void CustomPropertyEditorDialog::on_actionPropertyDuplicate_triggered() { ui->propertyWidget->duplicateProperty(); } void CustomPropertyEditorDialog::on_actionPropertyOptions_triggered() { ui->propertyWidget->propertyOptions(); } void CustomPropertyEditorDialog::updateActions(QtnPropertyBase *property) { auto widget = ui->propertyWidget; bool readOnly = widget->isReadOnly(); if (nullptr == property) property = ui->propertyWidget->propertyView()->activeProperty(); auto add_text = tr("New..."); auto var_property = QtnCustomPropertyWidget::getVarProperty(property); if (nullptr != var_property) { switch (var_property->GetType()) { case VarProperty::Map: add_text = tr("New Property..."); break; case VarProperty::List: add_text = tr("New Element..."); break; default: break; } bool not_top_parent = (var_property != var_property->TopParent()); ui->actionPropertyAdd->setEnabled( !readOnly && property->id() == VarProperty::PID_EXTRA); ui->actionPropertyDuplicate->setEnabled(!readOnly && not_top_parent); ui->actionPropertyOptions->setEnabled(true); ui->actionPropertyDelete->setEnabled( !readOnly && not_top_parent && widget->canDeleteProperty(property)); } else { ui->actionPropertyAdd->setEnabled(false); ui->actionPropertyDuplicate->setEnabled(false); ui->actionPropertyOptions->setEnabled(false); ui->actionPropertyDelete->setEnabled(false); } ui->actionPropertyAdd->setText(add_text); ui->actionPropertyCut->setEnabled(widget->canCutToClipboard()); ui->actionPropertyCopy->setEnabled(widget->canCopyToClipboard()); ui->actionPropertyPaste->setEnabled(widget->canPasteFromClipboard()); } void CustomPropertyEditorDialog::updateTitle() { setWindowTitle(ui->propertyWidget->isReadOnly() ? tr("Read-only Properties") : tr("Edit Custom Properties")); } ================================================ FILE: QtnProperty/CustomPropertyEditorDialog.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "CustomPropertyOptionsDialog.h" #include "PropertyWidgetEx.h" #include #include #include namespace Ui { class CustomPropertyEditorDialog; } class QAbstractButton; class QtnProperty; class QtnPropertyBase; class QtnPropertySet; class VarProperty; class QTN_IMPORT_EXPORT CustomPropertyEditorDialog : public QDialog { Q_OBJECT public: explicit CustomPropertyEditorDialog(QWidget *parent = nullptr); virtual ~CustomPropertyEditorDialog() override; bool execute(const QString &title, QVariant &data); void setReadOnly(bool value); virtual void accept() override; virtual void reject() override; signals: void apply(const QVariant &data); private slots: void onActivePropertyChanged(QtnPropertyBase *activeProperty); void on_buttonBox_clicked(QAbstractButton *button); void on_propertyWidget_customContextMenuRequested(const QPoint &pos); void on_actionPropertyAdd_triggered(); void on_actionPropertyDuplicate_triggered(); void on_actionPropertyOptions_triggered(); private: void updateActions(QtnPropertyBase *property = nullptr); void updateTitle(); Ui::CustomPropertyEditorDialog *ui; }; ================================================ FILE: QtnProperty/CustomPropertyEditorDialog.ui ================================================ CustomPropertyEditorDialog 0 0 389 468 true true 0 6 6 6 6 Qt::StrongFocus Qt::CustomContextMenu true Qt::StrongFocus QDialogButtonBox::Cancel|QDialogButtonBox::Ok Ctrl+= Qt::WindowShortcut Delete Del Qt::WindowShortcut Duplicate... Duplicate Options... Options F2 Qt::WindowShortcut Cut Ctrl+X Qt::WindowShortcut Copy Ctrl+C Qt::WindowShortcut Paste Ctrl+V Qt::WindowShortcut QtnCustomPropertyWidget QWidget
QtnProperty/CustomPropertyWidget.h
1
================================================ FILE: QtnProperty/CustomPropertyOptionsDialog.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "CustomPropertyOptionsDialog.h" #include "ui_CustomPropertyOptionsDialog.h" #include #include #include #include #include #include BasePropertyDialog::BasePropertyDialog(QWidget *parent) : QDialog(parent) , result_index(-1) { setWindowFlags( (windowFlags() & ~(Qt::WindowContextHelpButtonHint | Qt::WindowMinMaxButtonsHint)) | Qt::MSWindowsFixedSizeDialogHint | Qt::CustomizeWindowHint); } void BasePropertyDialog::initWithCount( int actual_index, int existing_count, bool readonly) { if (actual_index < 0) actual_index = existing_count; result_index = -1; result_name = ""; GetLabel()->setText(index_label); GetNameEdit()->setVisible(false); auto index_edit = GetIndexEdit(); index_edit->setVisible(true); index_edit->setMinimum(0); index_edit->setMaximum(existing_count); index_edit->setValue(actual_index); index_edit->setReadOnly(readonly); } void BasePropertyDialog::initWithName(const QString &actual_name, const IsNameAvailableCB &is_name_available, bool readonly) { result_index = -1; result_name = ""; this->is_name_available = is_name_available; GetLabel()->setText(name_label); GetIndexEdit()->setVisible(false); auto name_edit = GetNameEdit(); name_edit->setVisible(true); name_edit->setText(actual_name); name_edit->setReadOnly(readonly); } bool BasePropertyDialog::execute() { show(); raise(); exec(); return result() == DialogCode::Accepted; } bool BasePropertyDialog::ValidateInput() { auto name_edit = GetNameEdit(); if (name_edit->isVisible()) { auto name = name_edit->text(); if (nullptr == is_name_available || is_name_available(name)) { result_name = name; } else { QMessageBox::critical(this, QApplication::applicationName(), tr("Property with name '%1' is already exist.").arg(name)); return false; } } else { result_index = GetIndexEdit()->value(); } return true; } void BasePropertyDialog::on_buttonBox_clicked(QAbstractButton *button) { switch (GetButtonBox()->buttonRole(button)) { case QDialogButtonBox::AcceptRole: { if (ValidateInput()) accept(); break; } case QDialogButtonBox::RejectRole: { reject(); break; } default: break; } } CustomPropertyOptionsDialog::CustomPropertyOptionsDialog(QWidget *parent) : BasePropertyDialog(parent) , ui(new Ui::CustomPropertyOptionsDialog) { ui->setupUi(this); index_label = tr("Index:"); name_label = tr("Name:"); } CustomPropertyOptionsDialog::~CustomPropertyOptionsDialog() { delete ui; } void CustomPropertyOptionsDialog::executeReadOnly() { setReadOnly(true); BasePropertyDialog::execute(); } bool CustomPropertyOptionsDialog::execute(QtnCustomPropertyData &result) { setReadOnly(false); if (BasePropertyDialog::execute()) { result.index = result_index; result.name = result_name; result.value = value_type; return true; } return false; } void CustomPropertyOptionsDialog::setType(QVariant::Type type) { switch (type) { case QVariant::List: ui->rbList->setChecked(true); break; case QVariant::Map: ui->rbDictionary->setChecked(true); break; case QVariant::Bool: ui->rbBoolean->setChecked(true); break; case QVariant::Int: case QVariant::UInt: case QVariant::LongLong: case QVariant::ULongLong: case QVariant::Double: ui->rbNumeric->setChecked(true); break; case QVariant::String: case QVariant::Char: case QVariant::Color: ui->rbString->setChecked(true); break; default: ui->rbNull->setChecked(true); break; } } void CustomPropertyOptionsDialog::setTypeBoxEnabled(bool value) { ui->typeBox->setEnabled(value); } void CustomPropertyOptionsDialog::setReadOnly(bool readOnly) { setTypeBoxEnabled(!readOnly); GetLabel()->setEnabled(!readOnly); GetNameEdit()->setEnabled(!readOnly); GetIndexEdit()->setEnabled(!readOnly); GetButtonBox()->setStandardButtons(readOnly ? QDialogButtonBox::Close : QDialogButtonBox::Ok | QDialogButtonBox::Cancel); } bool CustomPropertyOptionsDialog::ValidateInput() { if (BasePropertyDialog::ValidateInput()) { if (ui->rbNull->isChecked()) value_type.clear(); else if (ui->rbBoolean->isChecked()) value_type = false; else if (ui->rbNumeric->isChecked()) value_type = 0.0; else if (ui->rbString->isChecked()) value_type = ""; else if (ui->rbDictionary->isChecked()) value_type = QVariantMap(); else if (ui->rbList->isChecked()) value_type = QVariantList(); return true; } return false; } QLabel *CustomPropertyOptionsDialog::GetLabel() { return ui->label; } QLineEdit *CustomPropertyOptionsDialog::GetNameEdit() { return ui->editName; } QSpinBox *CustomPropertyOptionsDialog::GetIndexEdit() { return ui->editIndex; } QDialogButtonBox *CustomPropertyOptionsDialog::GetButtonBox() { return ui->buttonBox; } QString QtnCustomPropertyData::displayName() const { if (index >= 0) return nameForIndex(index); return name; } QString QtnCustomPropertyData::nameForIndex(int index) { return QStringLiteral("[%1]").arg(index); } ================================================ FILE: QtnProperty/CustomPropertyOptionsDialog.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "Config.h" #include #include #include class QLabel; class QLineEdit; class QSpinBox; class QDialogButtonBox; class QAbstractButton; typedef std::function IsNameAvailableCB; class QTN_IMPORT_EXPORT BasePropertyDialog : public QDialog { Q_OBJECT public: explicit BasePropertyDialog(QWidget *parent = nullptr); void initWithCount( int actual_index, int existing_count, bool readonly = false); void initWithName(const QString &actual_name, const IsNameAvailableCB &is_name_available, bool readonly = false); private slots: void on_buttonBox_clicked(QAbstractButton *button); protected: bool execute(); virtual bool ValidateInput(); virtual QLabel *GetLabel() = 0; virtual QLineEdit *GetNameEdit() = 0; virtual QSpinBox *GetIndexEdit() = 0; virtual QDialogButtonBox *GetButtonBox() = 0; IsNameAvailableCB is_name_available; int result_index; QString result_name; QString index_label; QString name_label; }; namespace Ui { class CustomPropertyOptionsDialog; } struct QTN_IMPORT_EXPORT QtnCustomPropertyData { int index; QString name; QVariant value; QString displayName() const; static QString nameForIndex(int index); }; class QTN_IMPORT_EXPORT CustomPropertyOptionsDialog : public BasePropertyDialog { Q_OBJECT public: explicit CustomPropertyOptionsDialog(QWidget *parent = nullptr); virtual ~CustomPropertyOptionsDialog() override; void executeReadOnly(); bool execute(QtnCustomPropertyData &result); void setType(QVariant::Type type); void setTypeBoxEnabled(bool value); void setReadOnly(bool readOnly); protected: virtual bool ValidateInput() override; virtual QLabel *GetLabel() override; virtual QLineEdit *GetNameEdit() override; virtual QSpinBox *GetIndexEdit() override; virtual QDialogButtonBox *GetButtonBox() override; QVariant value_type; Ui::CustomPropertyOptionsDialog *ui; }; ================================================ FILE: QtnProperty/CustomPropertyOptionsDialog.ui ================================================ CustomPropertyOptionsDialog Qt::NonModal 0 0 221 291 0 0 true 9 9 9 9 9 16777215 17 Name: 2 0 21 16777215 21 0 0 0 0 0 141 Type Numeric false String false Boolean Dictionary List Null true QDialogButtonBox::Cancel|QDialogButtonBox::Ok true ================================================ FILE: QtnProperty/CustomPropertyWidget.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "CustomPropertyWidget.h" #include "VarProperty.h" #include "PropertySet.h" #include "PropertyView.h" #include "Utils/InplaceEditing.h" #include "CustomPropertyOptionsDialog.h" #include #include #include #include #include #include #include #include #include #include #include static const QString kCustomPropertyData = QStringLiteral("QtnCustomPropertyData"); QtnCustomPropertyWidget::QtnCustomPropertyWidget(QWidget *parent) : QtnPropertyWidgetEx(parent) , dataPtr(nullptr) , lastAddType(QVariant::Invalid) , readOnly(false) , autoUpdate(false) , backupAutoUpdate(false) , rootSet(nullptr) { } void QtnCustomPropertyWidget::setReadOnly(bool value) { if (!readOnly) { readOnly = value; if (nullptr != rootSet) { rootSet->switchState(QtnPropertyStateImmutable, value, true); } } } void QtnCustomPropertyWidget::setData( QVariant *dataPtr, const QString &title, bool force) { if (force || this->dataPtr != dataPtr) { this->dataPtr = dataPtr; setPropertySet(nullptr); delete rootSet; if (nullptr != dataPtr) { rootSet = new QtnPropertySet(this); if (readOnly) rootSet->setState(QtnPropertyStateImmutable, true); newProperty(rootSet, *dataPtr, title, -1, nullptr); setPropertySet(rootSet); } else rootSet = nullptr; } } bool QtnCustomPropertyWidget::canDeleteProperty(QtnPropertyBase *property) { if (readOnly || !property || !property->isWritable()) { return false; } auto var_property = getVarProperty(property); if (nullptr != var_property) return (var_property != var_property->TopParent()); return false; } bool QtnCustomPropertyWidget::canCutToClipboard() { return !readOnly && canDeleteProperty(propertyView()->activeProperty()); } bool QtnCustomPropertyWidget::canPasteFromClipboard() { if (readOnly) { return false; } auto p = getActiveProperty(); if (!p) { return false; } if (!p->isWritable()) { return false; } return QtnPropertyWidgetEx::canPasteFromClipboard(); } void QtnCustomPropertyWidget::addProperty() { if (readOnly) return; QtnPropertyBase *property; VarProperty *var_property; if (getActiveVarProperty(property, var_property)) { CustomPropertyOptionsDialog dialog(this); QtnCustomPropertyData result_data; switch (var_property->GetType()) { case VarProperty::List: { dialog.setWindowTitle(tr("New Element")); dialog.initWithCount(-1, var_property->GetChildrenCount()); break; } case VarProperty::Map: { dialog.setWindowTitle(tr("New Property")); dialog.initWithName(QString(), std::bind(&VarProperty::IsChildNameAvailable, var_property, std::placeholders::_1, nullptr)); break; } default: return; } dialog.setType(lastAddType); if (dialog.execute(result_data)) { lastAddType = result_data.value.type(); addProperty(property, result_data); } } } void QtnCustomPropertyWidget::duplicateProperty() { if (readOnly) return; QtnPropertyBase *property; VarProperty *var_property; if (getActiveVarProperty(property, var_property)) { CustomPropertyOptionsDialog dialog(this); QtnCustomPropertyData result_data; auto var_parent = var_property->VarParent(); switch (var_parent->GetType()) { case VarProperty::List: { dialog.setWindowTitle(tr("Duplicate Element")); dialog.initWithCount( var_property->GetIndex(), var_parent->GetChildrenCount()); break; } case VarProperty::Map: { dialog.setWindowTitle(tr("Duplicate Property")); dialog.initWithName(var_property->GetName(), std::bind(&VarProperty::IsChildNameAvailable, var_parent, std::placeholders::_1, nullptr)); break; } default: Q_ASSERT(false); break; } dialog.setType(var_property->GetVariantType()); dialog.setTypeBoxEnabled(false); if (dialog.execute(result_data)) duplicateProperty(property, result_data); } } void QtnCustomPropertyWidget::propertyOptions() { QtnPropertyBase *property; VarProperty *var_property; if (getActiveVarProperty(property, var_property)) { CustomPropertyOptionsDialog dialog(this); QtnCustomPropertyData result_data; auto var_parent = var_property->VarParent(); dialog.setWindowTitle(tr("Property Options")); if (nullptr == var_parent) { dialog.initWithName(var_property->GetName(), nullptr, true); } else { switch (var_parent->GetType()) { case VarProperty::List: { dialog.setWindowTitle(tr("Element Options")); dialog.initWithCount(var_property->GetIndex(), var_parent->GetChildrenCount() - 1); break; } case VarProperty::Map: { dialog.initWithName(var_property->GetName(), std::bind(&VarProperty::IsChildNameAvailable, var_parent, std::placeholders::_1, var_property)); break; } default: Q_ASSERT(false); break; } } dialog.setType(var_property->GetVariantType()); if (readOnly) { dialog.executeReadOnly(); } else if (dialog.execute(result_data)) { auto old_data = var_property->CreateVariant(); switch (result_data.value.type()) { case QVariant::Bool: result_data.value = old_data.toBool(); break; case QVariant::Char: case QVariant::String: result_data.value = old_data.toString(); break; case QVariant::Int: case QVariant::UInt: case QVariant::LongLong: case QVariant::ULongLong: case QVariant::Double: result_data.value = old_data.toDouble(); break; default: if (var_property->GetType() == VarProperty::GetTypeFromValue(result_data.value)) result_data.value.swap(old_data); else { switch (var_property->GetType()) { case VarProperty::List: { if (result_data.value.type() == QVariant::Map) { old_data.clear(); QVariantMap result; for (auto property : var_property->GetChildren()) { result.insert(property->GetName(), property->CreateVariant()); } result_data.value = result; } break; } case VarProperty::Map: { if (result_data.value.type() == QVariant::List) { old_data.clear(); QVariantList result; for (auto property : var_property->GetChildren()) { result.push_back( property->CreateVariant()); } result_data.value = result; } break; } default: break; } } break; } updatePropertyOptions(property, result_data); } } } void QtnCustomPropertyWidget::setAutoUpdate(bool yes) { if (autoUpdate != yes) { autoUpdate = yes; if (yes) updateData(); } } void QtnCustomPropertyWidget::onPropertyValueAccept( void *valueToAccept, bool *accept) { if (nullptr != accept) { bool ok = VarProperty::PropertyValueAccept( qobject_cast(sender()), valueToAccept); Q_ASSERT(ok); *accept = ok; if (autoUpdate) updateData(); } } void QtnCustomPropertyWidget::editData(const QVariant &oldValue) { emit dataEdited(oldValue); } bool QtnCustomPropertyWidget::dataHasSupportedFormats(const QMimeData *data) { if (nullptr != data) { return QtnPropertyWidgetEx::dataHasSupportedFormats(data) || data->hasFormat(kCustomPropertyData); } return false; } void QtnCustomPropertyWidget::deleteProperty(QtnPropertyBase *property) { if (!canDeleteProperty(property)) return; auto var_property = getVarProperty(property); if (nullptr != var_property) { if (var_property != var_property->TopParent()) { var_property->RemoveFromParent(); auto set = qobject_cast(property->parent()); auto &set_properties = set->childProperties(); auto active_property_index = set_properties.indexOf(propertyView()->activeProperty()); updateSet(set, active_property_index >= 0 ? active_property_index : set_properties.indexOf(property)); } } } QMimeData *QtnCustomPropertyWidget::getPropertyDataForAction( QtnPropertyBase *property, Qt::DropAction action) { auto varProperty = getVarProperty(property); if (nullptr != varProperty) { switch (action) { case Qt::MoveAction: case Qt::CopyAction: case Qt::IgnoreAction: { auto mime = new QMimeData; auto variant = varProperty->CreateVariant(); QJsonObject jobj; jobj.insert( varProperty->GetName(), QJsonValue::fromVariant(variant)); QJsonDocument doc; doc.setObject(jobj); QByteArray json(doc.toJson()); int start = json.indexOf('{') + 1; int end = json.lastIndexOf('}'); mime->setText( QString::fromUtf8(&json.constData()[start], end - start) .trimmed()); mime->setData(kCustomPropertyData, doc.toBinaryData()); return mime; } default: break; } } return nullptr; } bool QtnCustomPropertyWidget::insertReplaceOrCancel( QtnPropertyBase *destination, QtnCustomPropertyData &customData) { auto varProperty = getVarProperty(destination); Q_ASSERT(nullptr != varProperty); enum { CANCEL, INSERT, REPLACE }; int choice = REPLACE; auto insertDestination = qobject_cast(destination); if (nullptr == insertDestination) { if (varProperty != varProperty->TopParent()) insertDestination = qobject_cast(destination->parent()); } if (nullptr != insertDestination) { QMessageBox mb(QMessageBox::Question, QApplication::applicationDisplayName(), tr("Do you want to insert new property " "from clipboard or to replace the selected one?"), QMessageBox::Cancel, this); auto insertButton = mb.addButton(tr("Insert", "Paste"), QMessageBox::AcceptRole); auto replaceButton = mb.addButton(tr("Replace", "Paste"), QMessageBox::AcceptRole); mb.setDefaultButton(replaceButton); mb.show(); mb.raise(); mb.exec(); if (mb.clickedButton() == insertButton) choice = INSERT; else if (mb.clickedButton() == replaceButton) choice = REPLACE; else choice = CANCEL; } switch (choice) { case INSERT: { if (insertDestination == destination) { switch (varProperty->GetType()) { case VarProperty::List: customData.index = varProperty->GetChildrenCount(); break; case VarProperty::Map: customData.index = -1; break; default: break; } } addProperty(insertDestination, customData); break; } case REPLACE: { customData.name = varProperty->GetName(); updatePropertyOptions(destination, customData); break; } default: return false; } return true; } bool QtnCustomPropertyWidget::applyPropertyData(const QMimeData *data, QtnPropertyBase *destination, QtnApplyPosition position) { if (readOnly || !destination) return false; auto varProperty = getVarProperty(destination); if (nullptr != varProperty) { QtnCustomPropertyData customData; if (data->hasFormat(kCustomPropertyData)) { auto doc = QJsonDocument::fromBinaryData(data->data(kCustomPropertyData)); if (doc.isObject()) { auto obj = doc.object(); bool ok = false; int insertIndex = varProperty->GetIndex(); if (QtnApplyPosition::Over == position && varProperty->GetType() == VarProperty::Value) { position = QtnApplyPosition::After; } for (auto it = obj.begin(); it != obj.end(); ++it) { customData.value = it.value().toVariant(); switch (position) { case QtnApplyPosition::Before: case QtnApplyPosition::After: { if (varProperty != varProperty->TopParent()) { auto parent_prop = qobject_cast( destination->parent()); if (!parent_prop->isWritable()) { break; } switch (getVarProperty(parent_prop)->GetType()) { case VarProperty::Map: { customData.index = -1; customData.name = it.key(); addProperty(parent_prop, customData); ok = true; break; } case VarProperty::List: { customData.name.clear(); customData.index = insertIndex; if (QtnApplyPosition::After == position) customData.index++; addProperty(parent_prop, customData); ok = true; break; } default: break; } } break; } case QtnApplyPosition::Over: { if (!destination->isWritable()) { break; } switch (varProperty->GetType()) { case VarProperty::Map: { customData.index = -1; customData.name = it.key(); addProperty(destination, customData); ok = true; break; } case VarProperty::List: { customData.name.clear(); customData.index = varProperty->GetChildrenCount(); addProperty(destination, customData); ok = true; break; } default: break; } break; } case QtnApplyPosition::None: { if (!destination->isWritable()) { break; } customData.index = varProperty->GetIndex(); customData.name = it.key(); ok = insertReplaceOrCancel(destination, customData); break; } } insertIndex++; } if (ok) return true; } } else if (destination->isWritable()) { customData.index = varProperty->GetIndex(); customData.name = ""; if (data->hasColor()) { customData.value = data->colorData(); return insertReplaceOrCancel(destination, customData); } if (data->hasUrls()) { QVariantList list; for (auto &url : data->urls()) { if (url.isLocalFile()) list.push_back(url.toLocalFile()); else list.push_back(url.toString()); } if (list.size() > 1) { customData.value = list; } else { customData.value = list.at(0); } return insertReplaceOrCancel(destination, customData); } if (data->hasText()) { auto srcText = data->text().toUtf8(); auto text = srcText; text.prepend('{'); text.append('}'); QJsonParseError parseResult; auto doc = QJsonDocument::fromJson(text, &parseResult); if (QJsonParseError::NoError == parseResult.error) { auto object = doc.object(); if (object.size() == 1) { auto it = object.begin(); customData.name = it.key(); customData.value = it.value().toVariant(); return insertReplaceOrCancel(destination, customData); } if (object.size() > 1) { customData.value = object.toVariantMap(); return insertReplaceOrCancel(destination, customData); } } else { text = srcText; text.prepend('['); text.append(']'); doc = QJsonDocument::fromJson(text, &parseResult); if (QJsonParseError::NoError == parseResult.error) { auto array = doc.array(); if (array.size() == 1) { customData.value = array.at(0).toVariant(); return insertReplaceOrCancel( destination, customData); } if (array.size() > 1) { customData.value = array.toVariantList(); return insertReplaceOrCancel( destination, customData); } } } doc = QJsonDocument::fromJson(srcText, &parseResult); if (QJsonParseError::NoError == parseResult.error) { customData.value = doc.toVariant(); } else { customData.value = data->text(); } return insertReplaceOrCancel(destination, customData); } } } return false; } void QtnCustomPropertyWidget::dropEvent(QDropEvent *event) { if (readOnly) { event->ignore(); return; } backupAutoUpdate = autoUpdate; autoUpdate = false; QtnPropertyWidgetEx::dropEvent(event); } void QtnCustomPropertyWidget::dropEnd() { if (readOnly) return; QtnPropertyWidgetEx::dropEnd(); autoUpdate = backupAutoUpdate; if (autoUpdate) updateData(); } void QtnCustomPropertyWidget::updateData() { if (!readOnly && nullptr != dataPtr && nullptr != rootSet) { auto varProperty = getVarProperty(rootSet->childProperties().at(0)); auto oldValue = *dataPtr; *dataPtr = varProperty->CreateVariant(); editData(oldValue); } } void QtnCustomPropertyWidget::updateSet( QtnPropertyBase *setProperty, int childIndex) { Q_ASSERT(nullptr != setProperty); auto varProperty = getVarProperty(setProperty); Q_ASSERT(nullptr != varProperty); auto data = varProperty->CreateVariant(); auto var_parent = varProperty->VarParent(); varProperty->RemoveFromParent(); auto new_set = newProperty(nullptr, data, varProperty->GetName(), varProperty->GetIndex(), var_parent) ->asPropertySet(); Q_ASSERT(nullptr != new_set); auto property_parent = qobject_cast(setProperty->parent()); Q_ASSERT(nullptr != property_parent); int property_index = property_parent->childProperties().indexOf(setProperty); property_parent->removeChildProperty(setProperty); delete setProperty; property_parent->addChildProperty(new_set, true, property_index); auto view = propertyView(); auto &child_properties = new_set->childProperties(); if (child_properties.isEmpty()) view->setActiveProperty(new_set); else { int count = child_properties.count(); if (childIndex >= count) childIndex = count - 1; view->setActiveProperty(child_properties.at(childIndex)); } if (autoUpdate) updateData(); } bool QtnCustomPropertyWidget::getActiveVarProperty( QtnPropertyBase *&property, VarProperty *&varProperty) { property = propertyView()->activeProperty(); varProperty = getVarProperty(property); return varProperty != nullptr; } VarProperty *QtnCustomPropertyWidget::getVarProperty(QtnPropertyBase *source) { VarProperty *varProperty = nullptr; if (nullptr != source) { varProperty = source->findChild( QString(), Qt::FindDirectChildrenOnly); } return varProperty; } QtnPropertyBase *QtnCustomPropertyWidget::newProperty(QtnPropertySet *parent, const QVariant &value, const QString &key, int index, VarProperty *mapParent) { return VarProperty::NewExtraProperty( parent, value, key, index, mapParent, [this](QtnProperty *property) { QObject::connect(property, &QtnProperty::propertyValueAccept, this, &QtnCustomPropertyWidget::onPropertyValueAccept); }); } void QtnCustomPropertyWidget::addProperty( QtnPropertyBase *source, const QtnCustomPropertyData &data) { Q_ASSERT(nullptr != source); auto varProperty = getVarProperty(source); Q_ASSERT(nullptr != varProperty); auto set = source->asPropertySet(); Q_ASSERT(nullptr != set); if (data.index >= 0) Q_ASSERT(data.index <= varProperty->GetChildrenCount()); auto new_property = newProperty(nullptr, data.value, data.name, data.index, varProperty); std::vector children; for (auto child : set->childProperties()) { children.push_back(child); } if (data.index >= 0) children.insert(children.begin() + data.index, new_property); else children.push_back(new_property); auto isList = (VarProperty::List == varProperty->GetType()); if (isList) { int count = static_cast(children.size()); for (int i = 0; i < count; i++) { auto property = children.at(i); auto var_property = getVarProperty(property); var_property->SetIndex(i); property->setName(var_property->GetName()); } } else { std::sort(children.begin(), children.end(), [](QtnPropertyBase *a, QtnPropertyBase *b) -> bool { return QString::localeAwareCompare(a->name(), b->name()) < 0; }); } auto it = std::find(children.begin(), children.end(), new_property); set->addChildProperty(new_property, true, int(it - children.begin())); propertyView()->setActiveProperty(new_property, true); if (autoUpdate) updateData(); } void QtnCustomPropertyWidget::duplicateProperty( QtnPropertyBase *source, const QtnCustomPropertyData &data) { auto varProperty = getVarProperty(source); Q_ASSERT(nullptr != varProperty); auto set = qobject_cast(source->parent()); Q_ASSERT(nullptr != set); addProperty(set, { data.index, data.name, varProperty->CreateVariant() }); } void QtnCustomPropertyWidget::updatePropertyOptions( QtnPropertyBase *source, const QtnCustomPropertyData &data) { auto varProperty = getVarProperty(source); Q_ASSERT(nullptr != varProperty); auto set = qobject_cast(source->parent()); Q_ASSERT(nullptr != set); bool refresh_siblings = false; int old_index = varProperty->GetIndex(); bool top_property = (varProperty == varProperty->TopParent()); if (!top_property) { refresh_siblings = varProperty->SetIndex(data.index); refresh_siblings = varProperty->SetName(data.name) || refresh_siblings; } auto var_parent = varProperty->VarParent(); if (!refresh_siblings) { int index = set->childProperties().indexOf(source); QString prop_name(top_property ? varProperty->GetName() : data.name); varProperty->RemoveFromParent(); set->removeChildProperty(source); delete source; auto new_property = newProperty(nullptr, data.value, prop_name, data.index, var_parent); set->addChildProperty(new_property, true, index); propertyView()->setActiveProperty(new_property, true); if (autoUpdate) updateData(); } else { varProperty->SetValue(data.value); int index = data.index; auto children = var_parent->GetChildren(); if (index < 0) { std::sort(children.begin(), children.end(), [](VarProperty *a, VarProperty *b) -> bool { return QString::localeAwareCompare( a->GetName(), b->GetName()) < 0; }); auto it = std::find(children.begin(), children.end(), varProperty); index = int(it - children.begin()); } else if (old_index != index) { children.at(index)->SetIndex(old_index); } updateSet(set, index); } } ================================================ FILE: QtnProperty/CustomPropertyWidget.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "PropertyWidgetEx.h" #include class VarProperty; struct QtnCustomPropertyData; class QTN_IMPORT_EXPORT QtnCustomPropertyWidget : public QtnPropertyWidgetEx { Q_OBJECT public: explicit QtnCustomPropertyWidget(QWidget *parent = nullptr); inline bool isReadOnly() const; void setReadOnly(bool value); inline QVariant *getData() const; void setData(QVariant *dataPtr, const QString &title = QString(), bool force = false); virtual bool canDeleteProperty(QtnPropertyBase *property) override; virtual bool canCutToClipboard() override; virtual bool canPasteFromClipboard() override; void addProperty(); void duplicateProperty(); void propertyOptions(); inline bool isAutoUpdate() const; void setAutoUpdate(bool yes); void updateData(); static VarProperty *getVarProperty(QtnPropertyBase *source); signals: void dataEdited(const QVariant &oldValue); private: void onPropertyValueAccept(void *valueToAccept, bool *accept); protected: virtual void editData(const QVariant &oldValue); virtual bool dataHasSupportedFormats(const QMimeData *data) override; virtual void deleteProperty(QtnPropertyBase *property) override; virtual QMimeData *getPropertyDataForAction( QtnPropertyBase *property, Qt::DropAction dropAction) override; virtual bool applyPropertyData(const QMimeData *data, QtnPropertyBase *destination, QtnApplyPosition position) override; virtual void dropEvent(QDropEvent *event) override; virtual void dropEnd() override; private: void updateSet(QtnPropertyBase *setProperty, int childIndex); bool getActiveVarProperty( QtnPropertyBase *&property, VarProperty *&varProperty); QtnPropertyBase *newProperty(QtnPropertySet *parent, const QVariant &value, const QString &key, int index, VarProperty *mapParent); void addProperty( QtnPropertyBase *source, const QtnCustomPropertyData &data); void duplicateProperty( QtnPropertyBase *source, const QtnCustomPropertyData &data); void updatePropertyOptions( QtnPropertyBase *source, const QtnCustomPropertyData &data); bool insertReplaceOrCancel( QtnPropertyBase *destination, QtnCustomPropertyData &customData); QVariant *dataPtr; QVariant::Type lastAddType; bool readOnly : 1; bool autoUpdate : 1; bool backupAutoUpdate : 1; protected: QtnPropertySet *rootSet; }; bool QtnCustomPropertyWidget::isReadOnly() const { return readOnly; } QVariant *QtnCustomPropertyWidget::getData() const { return dataPtr; } bool QtnCustomPropertyWidget::isAutoUpdate() const { return autoUpdate; } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateBool.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateBool.h" #include "QtnProperty/Core/PropertyBool.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include "QtnProperty/PropertyView.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include #include #include #include #include QByteArray qtnLabelFalseAttr() { return QByteArrayLiteral("labelFalse"); } QByteArray qtnLabelTrueAttr() { return QByteArrayLiteral("labelTrue"); } class QtnPropertyBoolComboBoxHandler : public QtnPropertyEditorHandlerVT { public: QtnPropertyBoolComboBoxHandler( QtnPropertyDelegate *delegate, QComboBox &editor); protected: virtual void updateEditor() override; private: void onCurrentIndexChanged(int index); }; QtnPropertyDelegateBoolCheck::QtnPropertyDelegateBoolCheck( QtnPropertyBoolBase &owner) : QtnPropertyDelegateTyped(owner) { } void QtnPropertyDelegateBoolCheck::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyBoolBase::staticMetaObject, &qtnCreateDelegate, qtnCheckBoxDelegate()); } bool QtnPropertyDelegateBoolCheck::createSubItemValueImpl( QtnDrawContext &context, QtnSubItem &subItemValue) { subItemValue.trackState(); subItemValue.rect.adjust(context.widget->valueLeftMargin(), 0, 0, 0); subItemValue.rect.setWidth( context.style()->pixelMetric(QStyle::PM_IndicatorWidth)); subItemValue.drawHandler = [this](QtnDrawContext &context, const QtnSubItem &item) { QStyleOptionButton opt; opt.rect = item.rect; opt.state = state(context.isActive, item); if (stateProperty()->isMultiValue()) { opt.state |= QStyle::State_NoChange; } else { bool value = owner().value(); opt.state |= (value ? QStyle::State_On : QStyle::State_Off); } context.painter->drawControl(QStyle::CE_CheckBox, opt); }; subItemValue.eventHandler = [this](QtnEventContext &context, const QtnSubItem &, QtnPropertyToEdit *toEdit) { bool toggleValue = false; switch (context.eventType()) { case QEvent::MouseButtonRelease: toggleValue = true; break; case QEvent::KeyPress: { int key = context.eventAs()->key(); toggleValue = (key == Qt::Key_Space) || (key == Qt::Key_Return); break; } default: return false; } if (toggleValue) { toEdit->setup(property(), [this]() -> QWidget * { QtnPropertyDelegateBoolCheck *thiz = this; auto &p = thiz->owner(); p.setValue(!p.value(), editReason()); return nullptr; }); } return true; }; return true; } QtnPropertyDelegateBoolCombobox::QtnPropertyDelegateBoolCombobox( QtnPropertyBoolBase &owner) : QtnPropertyDelegateTyped(owner) { m_labels[0] = QtnPropertyBool::getBoolText(false, false); m_labels[1] = QtnPropertyBool::getBoolText(true, false); } void QtnPropertyDelegateBoolCombobox::Register( QtnPropertyDelegateFactory &factory) { factory.registerDelegate(&QtnPropertyBoolBase::staticMetaObject, &qtnCreateDelegate, qtnComboBoxDelegate()); } void QtnPropertyDelegateBoolCombobox::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnLabelFalseAttr(), m_labels[0]); info.loadAttribute(qtnLabelTrueAttr(), m_labels[1]); } QWidget *QtnPropertyDelegateBoolCombobox::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { QComboBox *comboBox = new QtnPropertyComboBox(this, parent); comboBox->addItem(m_labels[0], false); comboBox->addItem(m_labels[1], true); comboBox->setGeometry(rect); // connect widget and property new QtnPropertyBoolComboBoxHandler(this, *comboBox); if (inplaceInfo && stateProperty()->isEditableByUser()) comboBox->showPopup(); return comboBox; } bool QtnPropertyDelegateBoolCombobox::propertyValueToStrImpl( QString &strValue) const { strValue = m_labels[owner().value() ? 1 : 0]; return true; } QtnPropertyBoolComboBoxHandler::QtnPropertyBoolComboBoxHandler( QtnPropertyDelegate *delegate, QComboBox &editor) : QtnPropertyEditorHandlerVT(delegate, editor) { updateEditor(); QObject::connect(&editor, static_cast(&QComboBox::currentIndexChanged), this, &QtnPropertyBoolComboBoxHandler::onCurrentIndexChanged); } void QtnPropertyBoolComboBoxHandler::updateEditor() { updating++; editor().setEnabled(stateProperty()->isEditableByUser()); if (stateProperty()->isMultiValue()) editor().setCurrentIndex(-1); else { editor().setCurrentIndex(property().value() ? 1 : 0); } updating--; } void QtnPropertyBoolComboBoxHandler::onCurrentIndexChanged(int index) { if (index >= 0) { auto data = editor().itemData(index); if (data.canConvert()) { onValueChanged(data.toBool()); } } } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateBool.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_BOOL_H #define PROPERTY_DELEGATE_BOOL_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyBool.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateBoolCheck : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateBoolCheck) public: QtnPropertyDelegateBoolCheck(QtnPropertyBoolBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: bool createSubItemValueImpl( QtnDrawContext &context, QtnSubItem &subItemValue) override; }; class QTN_IMPORT_EXPORT QtnPropertyDelegateBoolCombobox : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateBoolCombobox) public: QtnPropertyDelegateBoolCombobox(QtnPropertyBoolBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; private: QString m_labels[2]; }; #endif // PROPERTY_DELEGATE_BOOL_H ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateDouble.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateDouble.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/Delegates/Utils/PropertyDelegateSliderBox.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Utils/DoubleSpinBox.h" #include "QtnProperty/MultiProperty.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include #include class QtnPropertyDoubleSpinBoxHandler : public QtnPropertyEditorHandlerVT { public: QtnPropertyDoubleSpinBoxHandler( QtnPropertyDelegateDouble *delegate, QDoubleSpinBox &editor); protected: virtual void updateEditor() override; virtual void updateValue() override; private: QtnPropertyDelegateDouble *m_delegate; }; QtnPropertyDelegateDouble::QtnPropertyDelegateDouble( QtnPropertyDoubleBase &owner) : QtnPropertyDelegateTyped(owner) , m_multiplier(1.0) , m_precision(std::numeric_limits::digits10 - 1) { } void QtnPropertyDelegateDouble::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyDoubleBase::staticMetaObject, &qtnCreateDelegate, qtnSpinBoxDelegate()); factory.registerDelegate(&QtnPropertyDoubleBase::staticMetaObject, &qtnCreateDelegate< QtnPropertyDelegateSlideBoxTyped, QtnPropertyDoubleBase>, qtnSliderBoxDelegate()); } double QtnPropertyDelegateDouble::stepValue() const { return m_step.isValid() ? m_step.toDouble() : owner().stepValue(); } QWidget *QtnPropertyDelegateDouble::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { auto spinBox = new QtnDoubleSpinBox(parent); spinBox->setDecimals(m_precision); spinBox->setSuffix(m_suffix); spinBox->setGeometry(rect); new QtnPropertyDoubleSpinBoxHandler(this, *spinBox); spinBox->selectAll(); if (stateProperty()->isEditableByUser()) qtnInitNumEdit(spinBox, inplaceInfo, NUM_FLOAT); return spinBox; } bool QtnPropertyDelegateDouble::acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const { if (QtnPropertyDelegateTyped:: acceptKeyPressedForInplaceEditImpl(keyEvent)) { return true; } return qtnAcceptForNumEdit(keyEvent, NUM_FLOAT); } bool QtnPropertyDelegateDouble::propertyValueToStrImpl(QString &strValue) const { strValue = QtnDoubleSpinBox::valueToText( currentValue(), QLocale(), m_precision, true); strValue.append(m_suffix); return true; } void QtnPropertyDelegateDouble::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnSuffixAttr(), m_suffix); info.loadAttribute(qtnMultiplierAttr(), m_multiplier); info.loadAttribute(qtnPrecisionAttr(), m_precision); m_step = info.attributes.value(qtnStepAttr()); if (m_step.isValid()) { bool ok; double step = m_step.toDouble(&ok); if (!ok) { m_step = QVariant(); } else { m_step = step; } } m_precision = qBound(0, m_precision, std::numeric_limits::digits10); m_min = info.attributes.value(qtnMinAttr()); m_max = info.attributes.value(qtnMaxAttr()); if (!qIsFinite(m_multiplier) || qFuzzyCompare(m_multiplier, 0.0)) { m_multiplier = 1.0; } fixMinMaxVariant(m_min, m_max); } double QtnPropertyDelegateDouble::minValue() const { return (m_min.isValid() ? m_min.toDouble() : owner().minValue()) * m_multiplier; } double QtnPropertyDelegateDouble::maxValue() const { return (m_max.isValid() ? m_max.toDouble() : owner().maxValue()) * m_multiplier; } double QtnPropertyDelegateDouble::multiplier() const { return m_multiplier; } double QtnPropertyDelegateDouble::currentValue() const { return qBound(minValue(), owner().value() * m_multiplier, maxValue()); } QtnPropertyDoubleSpinBoxHandler::QtnPropertyDoubleSpinBoxHandler( QtnPropertyDelegateDouble *delegate, QDoubleSpinBox &editor) : QtnPropertyEditorHandlerVT(delegate, editor) , m_delegate(delegate) { updateEditor(); editor.setKeyboardTracking(false); editor.installEventFilter(this); QObject::connect(&editor, static_cast( &QDoubleSpinBox::valueChanged), this, &QtnPropertyDoubleSpinBoxHandler::onValueChanged); } void QtnPropertyDoubleSpinBoxHandler::updateEditor() { updating++; editor().setReadOnly(!stateProperty()->isEditableByUser()); editor().setSingleStep(m_delegate->stepValue()); editor().setRange(m_delegate->minValue(), m_delegate->maxValue()); if (stateProperty()->isMultiValue()) { editor().setValue(editor().minimum()); editor().setSpecialValueText( QtnMultiProperty::getMultiValuePlaceholder()); } else { editor().setValue(m_delegate->currentValue()); editor().setSpecialValueText(QString()); } editor().selectAll(); updating--; } void QtnPropertyDoubleSpinBoxHandler::updateValue() { if (this->propertyBase()) { this->property().setValue(newValue / m_delegate->multiplier(), this->delegate()->editReason()); } } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateDouble.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyDouble.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateDouble : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateDouble) QString m_suffix; double m_multiplier; int m_precision; QVariant m_min; QVariant m_max; QVariant m_step; public: QtnPropertyDelegateDouble(QtnPropertyDoubleBase &owner); static void Register(QtnPropertyDelegateFactory &factory); double stepValue() const; double minValue() const; double maxValue() const; double multiplier() const; double currentValue() const; protected: virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const override; virtual bool propertyValueToStrImpl(QString &strValue) const override; virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; }; ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateEnum.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateEnum.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include #include class QtnPropertyEnumComboBoxHandler : public QtnPropertyEditorHandlerVT { public: QtnPropertyEnumComboBoxHandler( QtnPropertyDelegate *delegate, QComboBox &editor); protected: virtual void updateEditor() override; private: void onCurrentIndexChanged(int index); }; void QtnPropertyDelegateEnum::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyEnumBase::staticMetaObject, &qtnCreateDelegate, qtnComboBoxDelegate()); } QtnPropertyDelegateEnum::QtnPropertyDelegateEnum(QtnPropertyEnumBase &owner) : QtnPropertyDelegateTyped(owner) { } QWidget *QtnPropertyDelegateEnum::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { const QtnEnumInfo *info = owner().enumInfo(); if (!info) return 0; QComboBox *combo = new QtnPropertyComboBox(this, parent); info->forEachEnumValue([combo](const QtnEnumValueInfo &value) -> bool { combo->addItem(value.displayName(), QVariant(value.value())); return true; }); combo->setGeometry(rect); new QtnPropertyEnumComboBoxHandler(this, *combo); if (inplaceInfo && stateProperty()->isEditableByUser()) combo->showPopup(); return combo; } bool QtnPropertyDelegateEnum::propertyValueToStrImpl(QString &strValue) const { const QtnEnumInfo *info = owner().enumInfo(); const QtnEnumValueInfo *valueInfo = info ? info->findByValue(owner().value()) : 0; if (!valueInfo) return false; strValue = valueInfo->displayName(); return true; } QtnPropertyEnumComboBoxHandler::QtnPropertyEnumComboBoxHandler( QtnPropertyDelegate *delegate, QComboBox &editor) : QtnPropertyEditorHandlerVT(delegate, editor) { updateEditor(); QObject::connect(&editor, static_cast(&QComboBox::currentIndexChanged), this, &QtnPropertyEnumComboBoxHandler::onCurrentIndexChanged); } void QtnPropertyEnumComboBoxHandler::updateEditor() { updating++; editor().setEnabled(stateProperty()->isEditableByUser()); if (stateProperty()->isMultiValue()) editor().setCurrentIndex(-1); else { int index = editor().findData(property().value()); editor().setCurrentIndex(index); } updating--; } void QtnPropertyEnumComboBoxHandler::onCurrentIndexChanged(int index) { if (index >= 0) { QVariant data = editor().itemData(index); if (data.canConvert()) onValueChanged(data.toInt()); } } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateEnum.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_ENUM_H #define PROPERTY_DELEGATE_ENUM_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyEnum.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateEnum : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateEnum) public: QtnPropertyDelegateEnum(QtnPropertyEnumBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; #endif // PROPERTY_DELEGATE_ENUM_H ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateEnumFlags.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateEnumFlags.h" #include "QtnProperty/Core/PropertyBool.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/MultiProperty.h" #include static QString enumFlagsProperty2Str(const QtnPropertyEnumFlagsBase &property) { QString text; auto enumInfo = property.enumInfo(); if (nullptr == enumInfo) return text; auto value = property.value(); if (value == 0) return text; for (const QtnEnumValueInfo &e : enumInfo->getVector()) { if (value & e.value()) { if (!text.isEmpty()) text += "|"; text += e.displayName(); } } return text; } class QtnPropertyEnumFlagsLineEditHandler : public QtnPropertyEditorHandler { public: QtnPropertyEnumFlagsLineEditHandler( QtnPropertyDelegate *delegate, QLineEdit &editor); protected: virtual void updateEditor() override; }; QtnPropertyDelegateEnumFlags::QtnPropertyDelegateEnumFlags( QtnPropertyEnumFlagsBase &owner) : QtnPropertyDelegateTypedEx(owner) { const QtnEnumInfo *enumInfo = owner.enumInfo(); if (enumInfo) { for (const QtnEnumValueInfo &e : enumInfo->getVector()) { if (e.state() == QtnEnumValueStateNone) { QtnEnumValueType enumValue = e.value(); auto flagProperty = new QtnPropertyBoolCallback; flagProperty->setDisplayName(e.displayName()); flagProperty->setName(e.name()); flagProperty->setDescription( QtnPropertyEnumFlags::getFlagLabelDescription( e.displayName(), owner.displayName())); flagProperty->setCallbackValueGet( [&owner, enumValue]() -> bool { return owner.value() & enumValue; }); flagProperty->setCallbackValueSet( [&owner, enumValue](bool value, QtnPropertyChangeReason reason) { if (value) owner.setValue(owner.value() | enumValue, reason); else owner.setValue(owner.value() & ~enumValue, reason); }); addSubProperty(flagProperty); } } } } void QtnPropertyDelegateEnumFlags::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyEnumFlagsBase::staticMetaObject, &qtnCreateDelegate, QByteArrayLiteral("FlagsList")); } QWidget *QtnPropertyDelegateEnumFlags::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { QLineEdit *lineEdit = new QLineEdit(parent); lineEdit->setGeometry(rect); new QtnPropertyEnumFlagsLineEditHandler(this, *lineEdit); if (inplaceInfo) { lineEdit->selectAll(); } return lineEdit; } bool QtnPropertyDelegateEnumFlags::propertyValueToStrImpl( QString &strValue) const { strValue = enumFlagsProperty2Str(owner()); return true; } QtnPropertyEnumFlagsLineEditHandler::QtnPropertyEnumFlagsLineEditHandler( QtnPropertyDelegate *delegate, QLineEdit &editor) : QtnPropertyEditorHandlerType(delegate, editor) { editor.setReadOnly(true); updateEditor(); } void QtnPropertyEnumFlagsLineEditHandler::updateEditor() { if (stateProperty()->isMultiValue()) { editor().clear(); editor().setPlaceholderText( QtnMultiProperty::getMultiValuePlaceholder()); } else { editor().setText(enumFlagsProperty2Str(property())); editor().setPlaceholderText(QString()); } } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateEnumFlags.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_ENUM_FLAGS_H #define PROPERTY_DELEGATE_ENUM_FLAGS_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyEnumFlags.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateEnumFlags : public QtnPropertyDelegateTypedEx { Q_DISABLE_COPY(QtnPropertyDelegateEnumFlags) public: QtnPropertyDelegateEnumFlags(QtnPropertyEnumFlagsBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; #endif // PROPERTY_DELEGATE_ENUM_FLAGS_H ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateFloat.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateFloat.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/Delegates/Utils/PropertyDelegateSliderBox.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Utils/DoubleSpinBox.h" #include "QtnProperty/MultiProperty.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include #include QByteArray qtnMultiplierAttr() { return QByteArrayLiteral("multiplier"); } QByteArray qtnPrecisionAttr() { return QByteArrayLiteral("precision"); } class QtnPropertyFloatSpinBoxHandler : public QtnPropertyEditorHandler { public: using Inherited = QtnPropertyEditorHandler; QtnPropertyFloatSpinBoxHandler( QtnPropertyDelegateFloat *delegate, QDoubleSpinBox &editor); void onValueChanged(double value); virtual void updateEditor() override; void updateValue(); private: QtnPropertyDelegateFloat *m_delegate; double newValue; unsigned updating; }; QtnPropertyDelegateFloat::QtnPropertyDelegateFloat(QtnPropertyFloatBase &owner) : QtnPropertyDelegateTyped(owner) , m_multiplier(1.0) , m_precision(std::numeric_limits::digits10 - 1) { } void QtnPropertyDelegateFloat::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyFloatBase::staticMetaObject, &qtnCreateDelegate, qtnSpinBoxDelegate()); factory.registerDelegate(&QtnPropertyFloatBase::staticMetaObject, &qtnCreateDelegate< QtnPropertyDelegateSlideBoxTyped, QtnPropertyFloatBase>, qtnSliderBoxDelegate()); } double QtnPropertyDelegateFloat::stepValue() const { if (m_step.isValid()) { return m_step.toDouble(); } float sv = owner().stepValue(); return qint64(sv * 100000.0) / 100000.0; } QWidget *QtnPropertyDelegateFloat::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { auto spinBox = new QtnDoubleSpinBox(parent); spinBox->setDecimals(m_precision); spinBox->setSuffix(m_suffix); spinBox->setGeometry(rect); new QtnPropertyFloatSpinBoxHandler(this, *spinBox); spinBox->selectAll(); if (stateProperty()->isEditableByUser()) qtnInitNumEdit(spinBox, inplaceInfo, NUM_FLOAT); return spinBox; } bool QtnPropertyDelegateFloat::acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const { if (QtnPropertyDelegateTyped< QtnPropertyFloatBase>::acceptKeyPressedForInplaceEditImpl(keyEvent)) { return true; } return qtnAcceptForNumEdit(keyEvent, NUM_FLOAT); } bool QtnPropertyDelegateFloat::propertyValueToStrImpl(QString &strValue) const { strValue = QtnDoubleSpinBox::valueToText( currentValue(), QLocale(), m_precision, true); strValue.append(m_suffix); return true; } void QtnPropertyDelegateFloat::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnSuffixAttr(), m_suffix); info.loadAttribute(qtnMultiplierAttr(), m_multiplier); info.loadAttribute(qtnPrecisionAttr(), m_precision); m_step = info.attributes.value(qtnStepAttr()); if (m_step.isValid()) { bool ok; float step = m_step.toDouble(&ok); if (!ok) { m_step = QVariant(); } else { m_step = step; } } m_precision = qBound(0, m_precision, std::numeric_limits::digits10); m_min = info.attributes.value(qtnMinAttr()); m_max = info.attributes.value(qtnMaxAttr()); if (!qIsFinite(m_multiplier) || qFuzzyCompare(m_multiplier, 0.0)) { m_multiplier = 1.0; } fixMinMaxVariant(m_min, m_max); } double QtnPropertyDelegateFloat::minValue() const { return (m_min.isValid() ? m_min.toFloat() : owner().minValue()) * m_multiplier; } double QtnPropertyDelegateFloat::maxValue() const { return (m_max.isValid() ? m_max.toFloat() : owner().maxValue()) * m_multiplier; } double QtnPropertyDelegateFloat::multiplier() const { return m_multiplier; } double QtnPropertyDelegateFloat::currentValue() const { return qBound(minValue(), owner().value() * m_multiplier, maxValue()); } QtnPropertyFloatSpinBoxHandler::QtnPropertyFloatSpinBoxHandler( QtnPropertyDelegateFloat *delegate, QDoubleSpinBox &editor) : Inherited(delegate, editor) , m_delegate(delegate) , updating(0) { newValue = this->property().value(); updateEditor(); editor.setKeyboardTracking(false); editor.installEventFilter(this); QObject::connect(&editor, static_cast( &QDoubleSpinBox::valueChanged), this, &QtnPropertyFloatSpinBoxHandler::onValueChanged); } void QtnPropertyFloatSpinBoxHandler::onValueChanged(double value) { if (updating > 0) return; newValue = value; updateValue(); } void QtnPropertyFloatSpinBoxHandler::updateEditor() { updating++; editor().setReadOnly(!stateProperty()->isEditableByUser()); editor().setSingleStep(m_delegate->stepValue()); editor().setRange(m_delegate->minValue(), m_delegate->maxValue()); if (stateProperty()->isMultiValue()) { editor().setValue(editor().minimum()); editor().setSpecialValueText( QtnMultiProperty::getMultiValuePlaceholder()); } else { editor().setValue(m_delegate->currentValue()); editor().setSpecialValueText(QString()); } editor().selectAll(); updating--; } void QtnPropertyFloatSpinBoxHandler::updateValue() { if (this->propertyBase()) { this->property().setValue(newValue / m_delegate->multiplier(), this->delegate()->editReason()); } } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateFloat.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyFloat.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateFloat : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateFloat) QString m_suffix; double m_multiplier; int m_precision; QVariant m_min; QVariant m_max; QVariant m_step; public: QtnPropertyDelegateFloat(QtnPropertyFloatBase &owner); static void Register(QtnPropertyDelegateFactory &factory); double stepValue() const; double minValue() const; double maxValue() const; double multiplier() const; double currentValue() const; protected: virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const override; virtual bool propertyValueToStrImpl(QString &strValue) const override; virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; }; ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateInt.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateInt.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/Delegates/Utils/PropertyDelegateSliderBox.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/MultiProperty.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include #include #include QByteArray qtnSpinBoxDelegate() { return QByteArrayLiteral("SpinBox"); } QByteArray qtnSliderBoxDelegate() { return QByteArrayLiteral("SliderBox"); } QByteArray qtnSuffixAttr() { return QByteArrayLiteral("suffix"); } QByteArray qtnMinAttr() { return QByteArrayLiteral("min"); } QByteArray qtnMaxAttr() { return QByteArrayLiteral("max"); } QByteArray qtnStepAttr() { return QByteArrayLiteral("step"); } void qtnInitPercentSpinBoxDelegate(QtnPropertyDelegateInfo &delegate) { delegate.name = qtnSpinBoxDelegate(); delegate.attributes[qtnSuffixAttr()] = QLocale().percent(); } void qtnInitDegreeSpinBoxDelegate(QtnPropertyDelegateInfo &delegate) { delegate.name = qtnSpinBoxDelegate(); delegate.attributes[qtnSuffixAttr()] = QString::fromUtf8("º"); } class QtnPropertyIntSpinBoxHandler : public QtnPropertyEditorHandlerVT { public: QtnPropertyIntSpinBoxHandler( QtnPropertyDelegateInt *delegate, QSpinBox &editor); protected: virtual void updateEditor() override; private: QtnPropertyDelegateInt *m_delegate; }; QtnPropertyDelegateInt::QtnPropertyDelegateInt(QtnPropertyIntBase &owner) : QtnPropertyDelegateTyped(owner) { } void QtnPropertyDelegateInt::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyIntBase::staticMetaObject, &qtnCreateDelegate, qtnSpinBoxDelegate()); factory.registerDelegate(&QtnPropertyIntBase::staticMetaObject, &qtnCreateDelegate, QtnPropertyIntBase>, qtnSliderBoxDelegate()); } int QtnPropertyDelegateInt::stepValue() const { return m_step.isValid() ? m_step.toInt() : owner().stepValue(); } int QtnPropertyDelegateInt::minValue() const { return m_min.isValid() ? m_min.toInt() : owner().minValue(); } int QtnPropertyDelegateInt::maxValue() const { return m_max.isValid() ? m_max.toInt() : owner().maxValue(); } int QtnPropertyDelegateInt::currentValue() const { return qBound(minValue(), owner().value(), maxValue()); } QWidget *QtnPropertyDelegateInt::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { auto spinBox = new QSpinBox(parent); spinBox->setSuffix(m_suffix); spinBox->setGeometry(rect); new QtnPropertyIntSpinBoxHandler(this, *spinBox); spinBox->selectAll(); if (stateProperty()->isEditableByUser()) qtnInitNumEdit(spinBox, inplaceInfo, NUM_SIGNED_INT); return spinBox; } bool QtnPropertyDelegateInt::acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const { if (QtnPropertyDelegateTyped< QtnPropertyIntBase>::acceptKeyPressedForInplaceEditImpl(keyEvent)) { return true; } return qtnAcceptForNumEdit(keyEvent, NUM_SIGNED_INT); } void QtnPropertyDelegateInt::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnSuffixAttr(), m_suffix); m_min = info.attributes.value(qtnMinAttr()); m_max = info.attributes.value(qtnMaxAttr()); m_step = info.attributes.value(qtnStepAttr()); if (m_step.isValid()) { bool ok; int step = m_step.toInt(&ok); if (!ok) { m_step = QVariant(); } else { m_step = step; } } fixMinMaxVariant(m_min, m_max); } bool QtnPropertyDelegateInt::propertyValueToStrImpl(QString &strValue) const { strValue = QLocale().toString(currentValue()); strValue.append(m_suffix); return true; } QtnPropertyIntSpinBoxHandler::QtnPropertyIntSpinBoxHandler( QtnPropertyDelegateInt *delegate, QSpinBox &editor) : QtnPropertyEditorHandlerVT(delegate, editor) , m_delegate(delegate) { updateEditor(); editor.setKeyboardTracking(false); editor.installEventFilter(this); QObject::connect(&editor, static_cast(&QSpinBox::valueChanged), this, &QtnPropertyIntSpinBoxHandler::onValueChanged); } void QtnPropertyIntSpinBoxHandler::updateEditor() { updating++; editor().setReadOnly(!stateProperty()->isEditableByUser()); editor().setSingleStep(m_delegate->stepValue()); editor().setRange(m_delegate->minValue(), m_delegate->maxValue()); if (stateProperty()->isMultiValue()) { editor().setValue(editor().minimum()); editor().setSpecialValueText( QtnMultiProperty::getMultiValuePlaceholder()); } else { editor().setValue(m_delegate->currentValue()); editor().setSpecialValueText(QString()); } editor().selectAll(); updating--; } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateInt.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_INT_H #define PROPERTY_DELEGATE_INT_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyInt.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateInt : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateInt) QString m_suffix; QVariant m_min; QVariant m_max; QVariant m_step; public: QtnPropertyDelegateInt(QtnPropertyIntBase &owner); static void Register(QtnPropertyDelegateFactory &factory); int stepValue() const; int minValue() const; int maxValue() const; int currentValue() const; protected: virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const override; virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; #endif // PROPERTY_DELEGATE_INT_H ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQPoint.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateQPoint.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include #include QByteArray qtnXDisplayNameAttr() { return QByteArrayLiteral("xDisplayName"); } QByteArray qtnXDescriptionAttr() { return QByteArrayLiteral("xDescription"); } QByteArray qtnYDisplayNameAttr() { return QByteArrayLiteral("yDisplayName"); } QByteArray qtnYDescriptionAttr() { return QByteArrayLiteral("yDescription"); } QtnPropertyDelegateQPoint::QtnPropertyDelegateQPoint( QtnPropertyQPointBase &owner) : QtnPropertyDelegateTypedEx(owner) { auto xProperty = owner.createXProperty(); addSubProperty(xProperty); auto yProperty = owner.createYProperty(); addSubProperty(yProperty); } void QtnPropertyDelegateQPoint::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyQPointBase::staticMetaObject, &qtnCreateDelegate, "XY"); } void qtnApplyQPointDelegateAttributes( QtnPropertyDelegate *to, const QtnPropertyDelegateInfo &info) { enum { X, Y, TOTAL }; Q_ASSERT(to->subPropertyCount() == TOTAL); static const QtnSubPropertyInfo KEYS[TOTAL] = { { X, QtnPropertyQPoint::xKey(), qtnXDisplayNameAttr(), qtnXDescriptionAttr() }, { Y, QtnPropertyQPoint::yKey(), qtnYDisplayNameAttr(), qtnYDescriptionAttr() }, }; to->applySubPropertyInfos(info, KEYS, TOTAL); } void QtnPropertyDelegateQPoint::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnSuffixAttr(), m_suffix); qtnApplyQPointDelegateAttributes(this, info); } QWidget *QtnPropertyDelegateQPoint::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { return createValueEditorLineEdit(parent, rect, true, inplaceInfo); } bool QtnPropertyDelegateQPoint::propertyValueToStrImpl(QString &strValue) const { auto value = owner().value(); QLocale locale; strValue = QtnPropertyQPoint::getToStringFormat().arg( locale.toString(value.x()) + m_suffix, locale.toString(value.y()) + m_suffix); return true; } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQPoint.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_QPOINT_H #define PROPERTY_DELEGATE_QPOINT_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyQPoint.h" class QtnPropertyQPointBase; class QTN_IMPORT_EXPORT QtnPropertyDelegateQPoint : public QtnPropertyDelegateTypedEx { Q_DISABLE_COPY(QtnPropertyDelegateQPoint) QString m_suffix; public: QtnPropertyDelegateQPoint(QtnPropertyQPointBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; #endif // PROPERTY_DELEGATE_QPOINT_H ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQPointF.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateQPointF.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Core/PropertyQPoint.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include "QtnProperty/Utils/DoubleSpinBox.h" #include #include QtnPropertyDelegateQPointF::QtnPropertyDelegateQPointF( QtnPropertyQPointFBase &owner) : QtnPropertyDelegateTypedEx(owner) , m_multiplier(1.0) , m_precision(std::numeric_limits::digits10 - 1) { addSubProperty(owner.createXProperty()); addSubProperty(owner.createYProperty()); } void QtnPropertyDelegateQPointF::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyQPointFBase::staticMetaObject, &qtnCreateDelegate, "QPointF"); } extern void qtnApplyQPointDelegateAttributes( QtnPropertyDelegate *to, const QtnPropertyDelegateInfo &info); void QtnPropertyDelegateQPointF::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnSuffixAttr(), m_suffix); info.loadAttribute(qtnMultiplierAttr(), m_multiplier); info.loadAttribute(qtnPrecisionAttr(), m_precision); m_precision = qBound(0, m_precision, std::numeric_limits::digits10); if (!qIsFinite(m_multiplier) || qFuzzyCompare(m_multiplier, 0.0)) { m_multiplier = 1; } qtnApplyQPointDelegateAttributes(this, info); } QWidget *QtnPropertyDelegateQPointF::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { return createValueEditorLineEdit(parent, rect, true, inplaceInfo); } bool QtnPropertyDelegateQPointF::propertyValueToStrImpl(QString &strValue) const { auto value = owner().value(); QLocale locale; strValue = QtnPropertyQPoint::getToStringFormat().arg( QtnDoubleSpinBox::valueToText( value.x() * m_multiplier, locale, m_precision, true) + m_suffix, QtnDoubleSpinBox::valueToText( value.y() * m_multiplier, locale, m_precision, true) + m_suffix); return true; } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQPointF.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_QPOINTF_H #define PROPERTY_DELEGATE_QPOINTF_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyQPointF.h" class QtnPropertyQPointFBase; class QTN_IMPORT_EXPORT QtnPropertyDelegateQPointF : public QtnPropertyDelegateTypedEx { Q_DISABLE_COPY(QtnPropertyDelegateQPointF) QString m_suffix; double m_multiplier; int m_precision; public: QtnPropertyDelegateQPointF(QtnPropertyQPointFBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; #endif // PROPERTY_DELEGATE_QPOINTF_H ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQRect.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateQRect.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Core/PropertyQSize.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include QByteArray qtnLTWHDelegateName() { return QByteArrayLiteral("LTWH"); } QByteArray qtnLTRBDelegateName() { return QByteArrayLiteral("LTRB"); } QByteArray qtnLeftDisplayNameAttr() { return QByteArrayLiteral("leftDisplayName"); } QByteArray qtnLeftDescriptionAttr() { return QByteArrayLiteral("leftDescription"); } QByteArray qtnTopDisplayNameAttr() { return QByteArrayLiteral("topDisplayName"); } QByteArray qtnTopDescriptionAttr() { return QByteArrayLiteral("topDescription"); } QByteArray qtnRightDisplayNameAttr() { return QByteArrayLiteral("rightDisplayName"); } QByteArray qtnRightDescriptionAttr() { return QByteArrayLiteral("rightDescription"); } QByteArray qtnBottomDisplayNameAttr() { return QByteArrayLiteral("bottomDisplayName"); } QByteArray qtnBottomDescriptionAttr() { return QByteArrayLiteral("bottomDescription"); } QByteArray qtnWidthDisplayNameAttr() { return QByteArrayLiteral("widthDisplayName"); } QByteArray qtnWidthDescriptionAttr() { return QByteArrayLiteral("widthDescription"); } QByteArray qtnHeightDisplayNameAttr() { return QByteArrayLiteral("heightDisplayName"); } QByteArray qtnHeightDescriptionAttr() { return QByteArrayLiteral("heightDescription"); } QtnPropertyDelegateQRect::QtnPropertyDelegateQRect( QtnPropertyQRectBase &owner, bool useCoordinates) : QtnPropertyDelegateTypedEx(owner) , m_coordinates(useCoordinates) { addSubProperty(owner.createLeftProperty(!m_coordinates)); addSubProperty(owner.createTopProperty(!m_coordinates)); if (m_coordinates) { addSubProperty(owner.createRightProperty(false)); addSubProperty(owner.createBottomProperty(false)); } else { addSubProperty(owner.createWidthProperty()); addSubProperty(owner.createHeightProperty()); } } static QtnPropertyDelegate *qtnCreateDelegateLTRB(QtnPropertyBase &owner) { auto theOwner = qobject_cast(&owner); if (!theOwner) return nullptr; return new QtnPropertyDelegateQRect(*theOwner, true); } void QtnPropertyDelegateQRect::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyQRectBase::staticMetaObject, &qtnCreateDelegate, qtnLTWHDelegateName()); factory.registerDelegate(&QtnPropertyQRectBase::staticMetaObject, &qtnCreateDelegateLTRB, qtnLTRBDelegateName()); } void qtnApplyQRectDelegateAttributes(QtnPropertyDelegate *to, const QtnPropertyDelegateInfo &info, bool coordinates) { enum { LEFT = 0, TOP = 1, WIDTH = 2, HEIGHT = 3, RIGHT = 2, BOTTOM = 3, TOTAL }; Q_ASSERT(to->subPropertyCount() == TOTAL); if (coordinates) { static const QtnSubPropertyInfo LTRB[TOTAL] = { { LEFT, QtnPropertyQRect::leftKey(), qtnLeftDisplayNameAttr(), qtnLeftDescriptionAttr() }, { TOP, QtnPropertyQRect::topKey(), qtnTopDisplayNameAttr(), qtnTopDescriptionAttr() }, { RIGHT, QtnPropertyQRect::rightKey(), qtnRightDisplayNameAttr(), qtnRightDescriptionAttr() }, { BOTTOM, QtnPropertyQRect::bottomKey(), qtnBottomDisplayNameAttr(), qtnBottomDescriptionAttr() }, }; to->applySubPropertyInfos(info, LTRB, TOTAL); } else { static const QtnSubPropertyInfo LTWH[TOTAL] = { { LEFT, QtnPropertyQRect::leftKey(), qtnLeftDisplayNameAttr(), qtnLeftDescriptionAttr() }, { TOP, QtnPropertyQRect::topKey(), qtnTopDisplayNameAttr(), qtnTopDescriptionAttr() }, { WIDTH, QtnPropertyQSize::widthKey(), qtnWidthDisplayNameAttr(), qtnWidthDescriptionAttr() }, { HEIGHT, QtnPropertyQSize::heightKey(), qtnHeightDisplayNameAttr(), qtnHeightDescriptionAttr() }, }; to->applySubPropertyInfos(info, LTWH, TOTAL); } } void QtnPropertyDelegateQRect::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { qtnApplyQRectDelegateAttributes(this, info, m_coordinates); } QWidget *QtnPropertyDelegateQRect::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { return createValueEditorLineEdit(parent, rect, true, inplaceInfo); } bool QtnPropertyDelegateQRect::propertyValueToStrImpl(QString &strValue) const { auto value = owner().value(); QLocale locale; strValue = QtnPropertyQRect::getToStringFormat(m_coordinates) .arg(locale.toString(value.left()), locale.toString(value.top()), locale.toString(m_coordinates ? value.right() : value.width()), locale.toString( m_coordinates ? value.bottom() : value.height())); return true; } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQRect.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_QRECT_H #define PROPERTY_DELEGATE_QRECT_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyQRect.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateQRect : public QtnPropertyDelegateTypedEx { Q_DISABLE_COPY(QtnPropertyDelegateQRect) bool m_coordinates; public: QtnPropertyDelegateQRect( QtnPropertyQRectBase &owner, bool useCoordinates = false); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; #endif // PROPERTY_DELEGATE_QRECT_H ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQRectF.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateQRectF.h" #include "QtnProperty/Core/PropertyQRect.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include "QtnProperty/Utils/DoubleSpinBox.h" #include QtnPropertyDelegateQRectF::QtnPropertyDelegateQRectF( QtnPropertyQRectFBase &owner, bool useCoordinates) : QtnPropertyDelegateTypedEx(owner) , m_coordinates(useCoordinates) , m_precision(std::numeric_limits::digits10 - 1) { addSubProperty(owner.createLeftProperty(!m_coordinates)); addSubProperty(owner.createTopProperty(!m_coordinates)); if (m_coordinates) { addSubProperty(owner.createRightProperty(false)); addSubProperty(owner.createBottomProperty(false)); } else { addSubProperty(owner.createWidthProperty()); addSubProperty(owner.createHeightProperty()); } } static QtnPropertyDelegate *qtnCreateDelegateLTRB(QtnPropertyBase &owner) { auto theOwner = qobject_cast(&owner); if (!theOwner) return nullptr; return new QtnPropertyDelegateQRectF(*theOwner, true); } void QtnPropertyDelegateQRectF::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyQRectFBase::staticMetaObject, &qtnCreateDelegate, qtnLTWHDelegateName()); factory.registerDelegate(&QtnPropertyQRectFBase::staticMetaObject, &qtnCreateDelegateLTRB, qtnLTRBDelegateName()); } extern void qtnApplyQRectDelegateAttributes(QtnPropertyDelegate *to, const QtnPropertyDelegateInfo &info, bool coordinates); void QtnPropertyDelegateQRectF::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnPrecisionAttr(), m_precision); m_precision = qBound(0, m_precision, std::numeric_limits::digits10); qtnApplyQRectDelegateAttributes(this, info, m_coordinates); } QWidget *QtnPropertyDelegateQRectF::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { return createValueEditorLineEdit(parent, rect, true, inplaceInfo); } bool QtnPropertyDelegateQRectF::propertyValueToStrImpl(QString &strValue) const { auto value = owner().value(); QLocale locale; strValue = QtnPropertyQRect::getToStringFormat(m_coordinates) .arg(QtnDoubleSpinBox::valueToText( value.left(), locale, m_precision, true), QtnDoubleSpinBox::valueToText( value.top(), locale, m_precision, true), QtnDoubleSpinBox::valueToText( m_coordinates ? value.right() : value.width(), locale, m_precision, true), QtnDoubleSpinBox::valueToText( m_coordinates ? value.bottom() : value.height(), locale, m_precision, true)); return true; } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQRectF.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_QRECTF_H #define PROPERTY_DELEGATE_QRECTF_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyQRectF.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateQRectF : public QtnPropertyDelegateTypedEx { Q_DISABLE_COPY(QtnPropertyDelegateQRectF) bool m_coordinates; int m_precision; public: QtnPropertyDelegateQRectF( QtnPropertyQRectFBase &owner, bool useCoordinates = false); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; private: enum { LEFT = 0, TOP = 1, WIDTH = 2, HEIGHT = 3, RIGHT = 2, BOTTOM = 3 }; }; #endif // PROPERTY_DELEGATE_QRECTF_H ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQSize.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateQSize.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include #include QtnPropertyDelegateQSize::QtnPropertyDelegateQSize(QtnPropertyQSizeBase &owner) : QtnPropertyDelegateTypedEx(owner) { addSubProperty(owner.createWidthProperty()); addSubProperty(owner.createHeightProperty()); } void QtnPropertyDelegateQSize::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyQSizeBase::staticMetaObject, &qtnCreateDelegate, "WH"); } void qtnApplyQSizeDelegateAttributes( QtnPropertyDelegate *to, const QtnPropertyDelegateInfo &info) { enum { WIDTH, HEIGHT, TOTAL }; Q_ASSERT(to->subPropertyCount() == TOTAL); static const QtnSubPropertyInfo KEYS[TOTAL] = { { WIDTH, QtnPropertyQSize::widthKey(), qtnWidthDisplayNameAttr(), qtnWidthDescriptionAttr() }, { HEIGHT, QtnPropertyQSize::heightKey(), qtnHeightDisplayNameAttr(), qtnHeightDescriptionAttr() }, }; to->applySubPropertyInfos(info, KEYS, TOTAL); } void QtnPropertyDelegateQSize::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { qtnApplyQSizeDelegateAttributes(this, info); } QWidget *QtnPropertyDelegateQSize::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { return createValueEditorLineEdit(parent, rect, true, inplaceInfo); } bool QtnPropertyDelegateQSize::propertyValueToStrImpl(QString &strValue) const { auto value = owner().value(); QLocale locale; strValue = QtnPropertyQSize::getToStringFormat().arg( locale.toString(value.width()), locale.toString(value.height())); return true; } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQSize.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_QSIZE_H #define PROPERTY_DELEGATE_QSIZE_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyQSize.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateQSize : public QtnPropertyDelegateTypedEx { Q_DISABLE_COPY(QtnPropertyDelegateQSize) public: QtnPropertyDelegateQSize(QtnPropertyQSizeBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; #endif // PROPERTY_DELEGATE_QSIZE_H ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQSizeF.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateQSizeF.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Core/PropertyQSize.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include "QtnProperty/Utils/DoubleSpinBox.h" #include #include QtnPropertyDelegateQSizeF::QtnPropertyDelegateQSizeF( QtnPropertyQSizeFBase &owner) : QtnPropertyDelegateTypedEx(owner) , m_precision(std::numeric_limits::digits10 - 1) { addSubProperty(owner.createWidthProperty()); addSubProperty(owner.createHeightProperty()); } void QtnPropertyDelegateQSizeF::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyQSizeFBase::staticMetaObject, &qtnCreateDelegate, "WH"); } extern void qtnApplyQSizeDelegateAttributes( QtnPropertyDelegate *to, const QtnPropertyDelegateInfo &info); void QtnPropertyDelegateQSizeF::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnPrecisionAttr(), m_precision); m_precision = qBound(0, m_precision, std::numeric_limits::digits10); qtnApplyQSizeDelegateAttributes(this, info); } QWidget *QtnPropertyDelegateQSizeF::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { return createValueEditorLineEdit(parent, rect, true, inplaceInfo); } bool QtnPropertyDelegateQSizeF::propertyValueToStrImpl(QString &strValue) const { auto value = owner().value(); QLocale locale; strValue = QtnPropertyQSize::getToStringFormat().arg( QtnDoubleSpinBox::valueToText(value.width(), locale, m_precision, true), QtnDoubleSpinBox::valueToText( value.height(), locale, m_precision, true)); return true; } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQSizeF.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_QSIZEF_H #define PROPERTY_DELEGATE_QSIZEF_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyQSizeF.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateQSizeF : public QtnPropertyDelegateTypedEx { Q_DISABLE_COPY(QtnPropertyDelegateQSizeF) int m_precision; public: QtnPropertyDelegateQSizeF(QtnPropertyQSizeFBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; #endif // PROPERTY_DELEGATE_QSIZEF_H ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQString.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2019 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateQString.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include "QtnProperty/MultiProperty.h" #include "QtnProperty/Utils/MultilineTextDialog.h" #include "QtnProperty/Utils/InplaceEditing.h" #include "QtnProperty/Utils/QtnCompleterLineEdit.h" #include "QtnProperty/PropertyView.h" #include #include #include #include #include #include #include #include #include #include #include static QString toSingleLine(const QString &str) { int n = str.indexOf('\n'); int r = str.indexOf('\r'); int len = n < 0 ? r : (r < 0 ? n : qMin(n, r)); return QString(str.data(), len); } QByteArray qtnMultiLineEditAttr() { return QByteArrayLiteral("multiline_edit"); } QByteArray qtnMaxLengthAttr() { return QByteArrayLiteral("max_length"); } QByteArray qtnPlaceholderAttr() { return QByteArrayLiteral("placeholder"); } QByteArray qtnItemsAttr() { return QByteArrayLiteral("items"); } QByteArray qtnEditableAttr() { return QByteArrayLiteral("editable"); } QByteArray qtnInvalidColorAttr() { return QByteArrayLiteral("invalidColor"); } QByteArray qtnShowRelativePathAttr() { return QByteArrayLiteral("showRelativePath"); } QByteArray qtnFileNameFilterAttr() { return QByteArrayLiteral("nameFilter"); } QByteArray qtnFileNameFiltersAttr() { return QByteArrayLiteral("nameFilters"); } QByteArray qtnDefaultSuffixAttr() { return QByteArrayLiteral("defaultSuffix"); } QByteArray qtnDefaultDirAttr() { return QByteArrayLiteral("defaultDirectory"); } QByteArray qtnOptionsAttr() { return QByteArrayLiteral("options"); } QByteArray qtnFileModeAttr() { return QByteArrayLiteral("fileMode"); } QByteArray qtnViewModeAttr() { return QByteArrayLiteral("viewMode"); } QByteArray qtnAcceptModeAttr() { return QByteArrayLiteral("acceptMode"); } QByteArray qtnGetCandidatesFnAttr() { return QByteArrayLiteral("GetCandidatesFn"); } QByteArray qtnCreateCandidateFnAttr() { return QByteArrayLiteral("CreateCandidateFn"); } QByteArray qtnCreateCandidateIconAttr() { return QByteArrayLiteral("CreateCandidateIcon"); } QByteArray qtnCreateCandidateToolTipAttr() { return QByteArrayLiteral("CreateCandidateToolTip"); } QByteArray qtnLineEditDelegate() { return QByteArrayLiteral("LineEdit"); } QByteArray qtnSelectFileDelegate() { return QByteArrayLiteral("File"); } QByteArray qtnCallbackDelegate() { return QByteArrayLiteral("Callback"); } class QtnPropertyQStringLineEditHandler : public QtnPropertyEditorHandler { public: QtnPropertyQStringLineEditHandler(QtnPropertyDelegate *delegate, QLineEdit &editor, const QString &placeholder); protected: virtual void updateEditor() override; void updateValue(); private: QString placeholder; }; class QtnPropertyQStringMultilineEditBttnHandler : public QtnPropertyEditorBttnHandler { public: QtnPropertyQStringMultilineEditBttnHandler(QtnPropertyDelegate *delegate, QtnLineEditBttn &editor, const QString &placeholder); protected: virtual void updateEditor() override; virtual void revertInput() override; virtual void onToolButtonClick() override; private: void onEditingFinished(); void onToolButtonClicked(bool); MultilineTextDialog *dialog; DialogContainerPtr dialogContainer; bool multiline; QString placeholder; }; QtnPropertyDelegateQString::QtnPropertyDelegateQString( QtnPropertyQStringBase &owner) : QtnPropertyDelegateTyped(owner) , m_maxLength(0x1000000) , m_multiline(true) { } void QtnPropertyDelegateQString::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyQStringBase::staticMetaObject, &qtnCreateDelegate, qtnLineEditDelegate()); } void QtnPropertyDelegateQString::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnMultiLineEditAttr(), m_multiline); info.loadAttribute(qtnMaxLengthAttr(), m_maxLength); info.loadAttribute(qtnPlaceholderAttr(), m_placeholder); } bool QtnPropertyDelegateQString::acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const { if (QtnPropertyDelegateTyped:: acceptKeyPressedForInplaceEditImpl(keyEvent)) return true; // accept any printable key return qtnAcceptForLineEdit(keyEvent); } QWidget *QtnPropertyDelegateQString::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { if (m_multiline) { QtnLineEditBttn *editor = new QtnLineEditBttn(parent); editor->setGeometry(rect); editor->lineEdit->setMaxLength(m_maxLength); editor->lineEdit->setPlaceholderText(m_placeholder); new QtnPropertyQStringMultilineEditBttnHandler( this, *editor, m_placeholder); qtnInitLineEdit(editor->lineEdit, inplaceInfo); return editor; } QLineEdit *lineEdit = new QLineEdit(parent); lineEdit->setMaxLength(m_maxLength); lineEdit->setPlaceholderText(m_placeholder); lineEdit->setGeometry(rect); new QtnPropertyQStringLineEditHandler(this, *lineEdit, m_placeholder); qtnInitLineEdit(lineEdit, inplaceInfo); return lineEdit; } bool QtnPropertyDelegateQString::propertyValueToStrImpl(QString &strValue) const { strValue = owner().value(); auto placeholder = strValue.isEmpty() && !m_placeholder.isEmpty() ? m_placeholder : QtnPropertyQString::getPlaceholderStr(strValue, m_multiline); if (!placeholder.isEmpty()) strValue.swap(placeholder); return true; } bool QtnPropertyDelegateQString::isPlaceholderColor() const { auto text = owner().value(); if (text.isEmpty() && !m_placeholder.isEmpty()) { return true; } return !QtnPropertyQString::getPlaceholderStr(text, m_multiline).isEmpty(); } class QtnPropertyQStringFileLineEditBttnHandler : public QtnPropertyEditorBttnHandler { public: QtnPropertyQStringFileLineEditBttnHandler( QtnPropertyDelegate *delegate, QtnLineEditBttn &editor); void applyAttributes(const QtnPropertyDelegateInfo &info); virtual void onToolButtonClick() override; virtual void updateEditor() override; private: void onToolButtonClicked(bool); void onEditingFinished(); QFileDialog *dialog; DialogContainerPtr dialogContainer; QString defaultDirectory; }; QtnPropertyDelegateQStringInvalidBase::QtnPropertyDelegateQStringInvalidBase( QtnPropertyQStringBase &owner) : QtnPropertyDelegateQString(owner) , m_invalidColor(Qt::red) { m_multiline = false; } void QtnPropertyDelegateQStringInvalidBase::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnInvalidColorAttr(), m_invalidColor); } void QtnPropertyDelegateQStringInvalidBase::drawValueImpl( QStylePainter &painter, const QRect &rect) const { QPen oldPen = painter.pen(); if ((m_invalidColor.alpha() != 0) && isNormalPainterState(painter) && !isPlaceholderColor() && !isPropertyValid() && stateProperty()->isEditableByUser()) { painter.setPen(m_invalidColor.rgb()); } QtnPropertyDelegateQString::drawValueImpl(painter, rect); painter.setPen(oldPen); } QtnPropertyDelegateQStringFile::QtnPropertyDelegateQStringFile( QtnPropertyQStringBase &owner) : QtnPropertyDelegateQStringInvalidBase(owner) { } void QtnPropertyDelegateQStringFile::Register( QtnPropertyDelegateFactory &factory) { factory.registerDelegate(&QtnPropertyQStringBase::staticMetaObject, &qtnCreateDelegate, qtnSelectFileDelegate()); } void QtnPropertyDelegateQStringFile::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { QtnPropertyDelegateQStringInvalidBase::applyAttributesImpl(info); m_editorAttributes = info; } bool QtnPropertyDelegateQStringFile::propertyValueToStrImpl( QString &strValue) const { if (!owner().value().isEmpty()) { strValue = QDir::toNativeSeparators( shouldShowRelativePath() ? relativeFilePath() : absoluteFilePath()); return true; } return QtnPropertyDelegateQStringInvalidBase::propertyValueToStrImpl( strValue); } bool QtnPropertyDelegateQStringFile::toolTipImpl(QString &strValue) const { strValue = QDir::toNativeSeparators(absoluteFilePath()); return true; } QWidget *QtnPropertyDelegateQStringFile::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { QtnLineEditBttn *editor = new QtnLineEditBttn(parent); editor->setGeometry(rect); auto handler = new QtnPropertyQStringFileLineEditBttnHandler(this, *editor); handler->applyAttributes(m_editorAttributes); qtnInitLineEdit(editor->lineEdit, inplaceInfo); return editor; } bool QtnPropertyDelegateQStringFile::isPropertyValid() const { auto filePath = absoluteFilePath(); if (filePath.isEmpty()) return true; auto fileMode = QFileDialog::FileMode(m_editorAttributes.getAttribute( qtnFileModeAttr(), QFileDialog::AnyFile)); switch (fileMode) { case QFileDialog::AnyFile: return true; case QFileDialog::ExistingFile: case QFileDialog::ExistingFiles: return QFileInfo(filePath).isFile(); case QFileDialog::Directory: case QFileDialog::DirectoryOnly: return QFileInfo(filePath).isDir(); } return false; } QString QtnPropertyDelegateQStringFile::defaultDirectory() const { return m_editorAttributes.getAttribute(qtnDefaultDirAttr(), QString()); } QString QtnPropertyDelegateQStringFile::absoluteFilePath() const { QString result = owner().value(); if (!result.isEmpty() && QDir::isRelativePath(result)) { auto defaultDir = defaultDirectory(); if (!defaultDir.isEmpty()) result = QDir(defaultDir).filePath(result); } return result; } QString QtnPropertyDelegateQStringFile::relativeFilePath() const { QString result = owner().value(); if (!result.isEmpty() && QDir::isAbsolutePath(result)) { auto defaultDir = defaultDirectory(); if (!defaultDir.isEmpty()) return QDir(defaultDir).relativeFilePath(result); } return result; } bool QtnPropertyDelegateQStringFile::shouldShowRelativePath() const { if (defaultDirectory().isEmpty()) return false; return m_editorAttributes.getAttribute(qtnShowRelativePathAttr(), false); } class QtnPropertyQStringListComboBoxHandler : public QtnPropertyEditorHandlerVT { public: QtnPropertyQStringListComboBoxHandler(QtnPropertyDelegate *delegate, QComboBox &editor, const QtnPropertyDelegateInfo &info); private: virtual void updateEditor() override; virtual void updateValue() override; }; QtnPropertyDelegateQStringList::QtnPropertyDelegateQStringList( QtnPropertyQStringBase &owner) : QtnPropertyDelegateQString(owner) { } void QtnPropertyDelegateQStringList::Register( QtnPropertyDelegateFactory &factory) { factory.registerDelegate(&QtnPropertyQStringBase::staticMetaObject, &qtnCreateDelegate, qtnComboBoxDelegate()); } void QtnPropertyDelegateQStringList::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { m_editorAttributes = info; } QWidget *QtnPropertyDelegateQStringList::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { QComboBox *editor = new QtnPropertyComboBox(this, parent); editor->setGeometry(rect); auto handler = new QtnPropertyQStringListComboBoxHandler( this, *editor, m_editorAttributes); Q_UNUSED(handler); if (inplaceInfo && stateProperty()->isEditableByUser()) { editor->showPopup(); } return editor; } QtnPropertyQStringListComboBoxHandler::QtnPropertyQStringListComboBoxHandler( QtnPropertyDelegate *delegate, QComboBox &editor, const QtnPropertyDelegateInfo &info) : QtnPropertyEditorHandlerVT(delegate, editor) { bool editable = false; info.loadAttribute(qtnEditableAttr(), editable); QStringList items; info.loadAttribute(qtnItemsAttr(), items); editor.clear(); editor.addItems(items); editor.setEditable(editable); editor.setAutoCompletion(false); if (editable) editor.installEventFilter(this); updateEditor(); QObject::connect(&editor, &QComboBox::currentTextChanged, this, &QtnPropertyQStringListComboBoxHandler::onValueChanged); } void QtnPropertyQStringListComboBoxHandler::updateEditor() { updating++; editor().setEnabled(stateProperty()->isEditableByUser()); auto lineEdit = editor().lineEdit(); if (stateProperty()->isMultiValue()) { editor().clearEditText(); if (lineEdit) { lineEdit->setPlaceholderText( QtnMultiProperty::getMultiValuePlaceholder()); } } else { editor().setCurrentText(property()); if (editor().currentText() != property().value()) editor().setCurrentIndex(-1); if (lineEdit) { lineEdit->setPlaceholderText(QString()); } } if (lineEdit) lineEdit->selectAll(); updating--; } void QtnPropertyQStringListComboBoxHandler::updateValue() { if (!editor().isEditable() || canApply()) { property().setValue(toSingleLine(newValue), delegate()->editReason()); } applyReset(); } QtnPropertyQStringFileLineEditBttnHandler:: QtnPropertyQStringFileLineEditBttnHandler( QtnPropertyDelegate *delegate, QtnLineEditBttn &editor) : QtnPropertyEditorHandlerType(delegate, editor) , dialog(new QFileDialog(&editor)) { dialogContainer = connectDialog(dialog); updateEditor(); editor.lineEdit->installEventFilter(this); QObject::connect(editor.toolButton, &QToolButton::clicked, this, &QtnPropertyQStringFileLineEditBttnHandler::onToolButtonClicked); QObject::connect(editor.lineEdit, &QLineEdit::editingFinished, this, &QtnPropertyQStringFileLineEditBttnHandler::onEditingFinished); } void QtnPropertyQStringFileLineEditBttnHandler::applyAttributes( const QtnPropertyDelegateInfo &info) { int option = 0; if (info.loadAttribute(qtnAcceptModeAttr(), option)) dialog->setAcceptMode(QFileDialog::AcceptMode(option)); QString str; if (info.loadAttribute(qtnDefaultSuffixAttr(), str)) dialog->setDefaultSuffix(str); if (info.loadAttribute(qtnDefaultDirAttr(), str)) defaultDirectory = str; if (info.loadAttribute(qtnFileModeAttr(), option)) dialog->setFileMode(QFileDialog::FileMode(option)); if (info.loadAttribute(qtnOptionsAttr(), option)) dialog->setOptions(QFileDialog::Options(QFlag(option))); if (info.loadAttribute(qtnViewModeAttr(), option)) dialog->setViewMode(QFileDialog::ViewMode(option)); if (info.loadAttribute(qtnFileNameFilterAttr(), str)) dialog->setNameFilter(str); QStringList list; if (info.loadAttribute(qtnFileNameFiltersAttr(), list)) dialog->setNameFilters(list); } void QtnPropertyQStringFileLineEditBttnHandler::onToolButtonClick() { onToolButtonClicked(false); } void QtnPropertyQStringFileLineEditBttnHandler::updateEditor() { bool editable = stateProperty()->isEditableByUser(); editor().lineEdit->setReadOnly(!editable); editor().toolButton->setEnabled(editable); auto path = QDir::toNativeSeparators(property().value()); editor().setTextForProperty(stateProperty(), path); if (!stateProperty()->isMultiValue()) { auto edit = editor().lineEdit; edit->setPlaceholderText( QtnPropertyQString::getPlaceholderStr(edit->text(), false)); edit->selectAll(); } } void QtnPropertyQStringFileLineEditBttnHandler::onToolButtonClicked(bool) { auto property = &this->property(); volatile bool destroyed = false; auto connection = QObject::connect(property, &QObject::destroyed, [&destroyed]() mutable { destroyed = true; }); reverted = true; auto dialogContainer = this->dialogContainer; QString filePath = property->value(); QString dirPath = this->defaultDirectory; QFileInfo fileInfo(filePath); if (!filePath.isEmpty()) { filePath = QDir(dirPath).filePath(filePath); fileInfo.setFile(filePath); dirPath = fileInfo.path(); } dialog->setDirectory(dirPath); dialog->selectFile(filePath); if (dialog->exec() == QDialog::Accepted && !destroyed) { QStringList files = dialog->selectedFiles(); if (files.size() == 1) property->setValue(QDir::toNativeSeparators(files.first()), delegate()->editReason()); } if (!destroyed) QObject::disconnect(connection); Q_UNUSED(dialogContainer); } void QtnPropertyQStringFileLineEditBttnHandler::onEditingFinished() { if (canApply()) { property().setValue( editor().lineEdit->text(), delegate()->editReason()); } applyReset(); } QtnPropertyQStringMultilineEditBttnHandler:: QtnPropertyQStringMultilineEditBttnHandler(QtnPropertyDelegate *delegate, QtnLineEditBttn &editor, const QString &placeholder) : QtnPropertyEditorHandlerType(delegate, editor) , dialog(new MultilineTextDialog(&editor)) , multiline(false) , placeholder(placeholder) { dialogContainer = connectDialog(dialog); updateEditor(); editor.lineEdit->installEventFilter(this); QObject::connect(editor.toolButton, &QToolButton::clicked, this, &QtnPropertyQStringMultilineEditBttnHandler::onToolButtonClicked); QObject::connect(editor.lineEdit, &QLineEdit::editingFinished, this, &QtnPropertyQStringMultilineEditBttnHandler::onEditingFinished); } void QtnPropertyQStringMultilineEditBttnHandler::updateEditor() { auto edit = editor().lineEdit; edit->setReadOnly(!stateProperty()->isEditableByUser()); if (stateProperty()->isMultiValue()) { edit->clear(); edit->setPlaceholderText(QtnMultiProperty::getMultiValuePlaceholder()); } else { auto text = property().value(); if (QtnPropertyQString::isMultilineText(text)) { multiline = true; edit->setText(QString()); } else { multiline = false; edit->setText(text); } if (text.isEmpty() && !placeholder.isEmpty()) { edit->setPlaceholderText(placeholder); } else { edit->setPlaceholderText( QtnPropertyQString::getPlaceholderStr(text, true)); } edit->selectAll(); } } void QtnPropertyQStringMultilineEditBttnHandler::revertInput() { reverted = true; } void QtnPropertyQStringMultilineEditBttnHandler::onToolButtonClick() { onToolButtonClicked(false); } void QtnPropertyQStringMultilineEditBttnHandler::onEditingFinished() { if (canApply()) { auto text = editor().lineEdit->text(); if (!multiline || !text.isEmpty()) { property().setValue(text, delegate()->editReason()); updateEditor(); } } applyReset(); } void QtnPropertyQStringMultilineEditBttnHandler::onToolButtonClicked(bool) { auto text = editor().lineEdit->text(); auto property = &this->property(); if (text.isEmpty() && multiline) { text = property->value(); } reverted = true; bool readonly = !stateProperty()->isEditableByUser(); auto dialogContainer = this->dialogContainer; dialog->setReadOnly(readonly); if (readonly) { dialog->setWindowTitle( QtnPropertyQString::getReadOnlyPropertyTitleFormat().arg( property->displayName())); } else { dialog->setWindowTitle(property->displayName()); } dialog->setText(text); dialog->show(); dialog->raise(); volatile bool destroyed = false; auto connection = QObject::connect(this, &QObject::destroyed, [&destroyed]() mutable { destroyed = true; }); if (dialog->exec() == QDialog::Accepted && !destroyed) property->setValue(dialog->getText(), delegate()->editReason()); if (!destroyed) { QObject::disconnect(connection); updateEditor(); } Q_UNUSED(dialogContainer); } QtnPropertyQStringLineEditHandler::QtnPropertyQStringLineEditHandler( QtnPropertyDelegate *delegate, QLineEdit &editor, const QString &placeholder) : QtnPropertyEditorHandler(delegate, editor) , placeholder(placeholder) { updateEditor(); editor.installEventFilter(this); QObject::connect(&editor, &QLineEdit::editingFinished, this, &QtnPropertyQStringLineEditHandler::updateValue); } void QtnPropertyQStringLineEditHandler::updateEditor() { editor().setReadOnly(!stateProperty()->isEditableByUser()); if (stateProperty()->isMultiValue()) { editor().clear(); editor().setPlaceholderText( QtnMultiProperty::getMultiValuePlaceholder()); } else { auto text = property().value(); editor().setText(text); editor().setPlaceholderText(text.isEmpty() && !placeholder.isEmpty() ? placeholder : QtnPropertyQString::getPlaceholderStr(text, false)); editor().selectAll(); } } void QtnPropertyQStringLineEditHandler::updateValue() { if (canApply()) { property().setValue( toSingleLine(editor().text()), delegate()->editReason()); } applyReset(); } class QtnPropertyQStringCandidatesComboBoxHandler : public QtnPropertyEditorHandlerVT { public: QtnPropertyQStringCandidatesComboBoxHandler( QtnPropertyDelegateQStringCallback *delegate, QtnCompleterLineEdit *lineEdit, QtnLineEditBttn &editor, const QString &placeholder); void shouldFinishEdit(); private: void updateCandidates(); void updatePlaceholder(const QString &text); virtual bool canApply() const override; virtual void updateEditor() override; virtual void revertInput() override; virtual bool eventFilter(QObject *watched, QEvent *event) override; void onItemActivated(); bool createNewCandidate(QString candidate); void onEditingFinished(); void onToolButtonClicked(); void connectLineEdit(); void disconnectLineEdit(); private: QtnGetCandidatesFn m_getCandidatesFn; QtnCreateCandidateFn m_createCandidateFn; QtnCompleterLineEdit *mLineEdit; QStringList m_candidates; QString m_placeholder; }; QtnPropertyDelegateQStringCallback::QtnPropertyDelegateQStringCallback( QtnPropertyQStringBase &owner) : QtnPropertyDelegateQString(owner) { } void QtnPropertyDelegateQStringCallback::Register( QtnPropertyDelegateFactory &factory) { factory.registerDelegate(&QtnPropertyQStringBase::staticMetaObject, &qtnCreateDelegate, qtnCallbackDelegate()); } void QtnPropertyDelegateQStringCallback::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { m_editorAttributes = info; } QWidget *QtnPropertyDelegateQStringCallback::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { auto lineEdit = new QtnCompleterLineEdit; auto editor = new QtnLineEditBttn(parent, QStringLiteral("*"), lineEdit); editor->setGeometry(rect); editor->lineEdit->setPlaceholderText(m_placeholder); new QtnPropertyQStringCandidatesComboBoxHandler( this, lineEdit, *editor, m_placeholder); qtnInitLineEdit(lineEdit, inplaceInfo); return editor; } QtnPropertyQStringCandidatesComboBoxHandler:: QtnPropertyQStringCandidatesComboBoxHandler( QtnPropertyDelegateQStringCallback *delegate, QtnCompleterLineEdit *lineEdit, QtnLineEditBttn &editor, const QString &placeholder) : QtnPropertyEditorHandlerVT(delegate, editor) , mLineEdit(lineEdit) , m_placeholder(placeholder) { auto model = new QStringListModel(&editor); auto completer = lineEdit->completer(); Q_ASSERT(completer); lineEdit->setCompleterModel(model); auto &attributes = delegate->m_editorAttributes; editor.toolButton->setIcon( attributes.getAttribute(qtnCreateCandidateIconAttr())); auto text = attributes.getAttribute(qtnCreateCandidateIconAttr()); if (!text.isEmpty()) { editor.toolButton->setText(text); } editor.toolButton->setToolTip( attributes.getAttribute(qtnCreateCandidateToolTipAttr())); attributes.loadAttribute(qtnCreateCandidateFnAttr(), m_createCandidateFn); attributes.loadAttribute(qtnGetCandidatesFnAttr(), m_getCandidatesFn); updateCandidates(); QtnPropertyQStringCandidatesComboBoxHandler::updateEditor(); mLineEdit->installEventFilter(this); completer->popup()->installEventFilter(this); completer->popup()->viewport()->installEventFilter(this); QObject::connect(editor.toolButton, &QToolButton::clicked, this, &QtnPropertyQStringCandidatesComboBoxHandler::onToolButtonClicked); connectLineEdit(); } void QtnPropertyQStringCandidatesComboBoxHandler::updateCandidates() { updating++; if (m_getCandidatesFn) m_candidates = m_getCandidatesFn(); auto completer = editor().lineEdit->completer(); Q_ASSERT(completer); Q_ASSERT(qobject_cast(completer->model())); auto model = static_cast(completer->model()); model->setStringList(m_candidates); updating--; } void QtnPropertyQStringCandidatesComboBoxHandler::updatePlaceholder( const QString &text) { QString placeholderStr; if (stateProperty()->isMultiValue()) { placeholderStr = QtnMultiProperty::getMultiValuePlaceholder(); } else if (text.isEmpty()) { if (m_placeholder.isEmpty()) { placeholderStr = QtnPropertyQString::getEmptyPlaceholderStr(); } else { placeholderStr = m_placeholder; } } else { placeholderStr = QtnPropertyQString::getPlaceholderStr(text, false); } editor().lineEdit->setPlaceholderText(placeholderStr); } bool QtnPropertyQStringCandidatesComboBoxHandler::canApply() const { return !reverted && returned && stateProperty() && stateProperty()->isEditableByUser(); } void QtnPropertyQStringCandidatesComboBoxHandler::updateEditor() { updating++; bool enabled = stateProperty()->isEditableByUser(); mLineEdit->setReadOnly(!enabled); if (stateProperty()->isMultiValue()) { mLineEdit->clear(); } else { mLineEdit->setText(property()); } updatePlaceholder(mLineEdit->text()); QMetaObject::invokeMethod(mLineEdit, "complete", Qt::QueuedConnection); mLineEdit->selectAll(); updating--; } void QtnPropertyQStringCandidatesComboBoxHandler::shouldFinishEdit() { QMetaObject::invokeMethod( mLineEdit, "editingFinished", Qt::QueuedConnection); } void QtnPropertyQStringCandidatesComboBoxHandler::revertInput() { if (updating) return; reverted = true; shouldFinishEdit(); } bool QtnPropertyQStringCandidatesComboBoxHandler::eventFilter( QObject *watched, QEvent *event) { switch (event->type()) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: case QEvent::MouseButtonDblClick: { auto me = static_cast(event); auto toolButton = editor().toolButton; auto localPos = toolButton->mapFromGlobal(me->globalPos()); if (toolButton->rect().contains(localPos)) { QObject *toolButtonObject = toolButton; QMouseEvent buttonEvent(event->type(), localPos, me->windowPos(), me->globalPos(), me->button(), me->buttons(), me->modifiers(), me->source()); toolButtonObject->event(&buttonEvent); return true; } break; } default: break; } return QObject::eventFilter(watched, event); } void QtnPropertyQStringCandidatesComboBoxHandler::onItemActivated() { if (updating) return; returned = true; shouldFinishEdit(); } bool QtnPropertyQStringCandidatesComboBoxHandler::createNewCandidate( QString candidate) { if (!m_createCandidateFn || updating) return false; qtnRetainInplaceEditor(); updating++; candidate = m_createCandidateFn(&editor(), candidate); updating--; if (!candidate.isEmpty()) { onValueChanged(candidate); updateCandidates(); } qtnReleaseInplaceEditor(); return !candidate.isEmpty(); } void QtnPropertyQStringCandidatesComboBoxHandler::onEditingFinished() { if (updating) return; disconnectLineEdit(); if (canApply()) { auto text = toSingleLine(mLineEdit->text()); if (!m_createCandidateFn || text.isEmpty() || m_candidates.contains(text, Qt::CaseInsensitive)) { property().setValue(text, delegate()->editReason()); } else { if (!createNewCandidate(text)) { applyReset(); connectLineEdit(); return; } } } applyReset(); qtnStopInplaceEdit(); } void QtnPropertyQStringCandidatesComboBoxHandler::onToolButtonClicked() { createNewCandidate(mLineEdit->text()); applyReset(); } void QtnPropertyQStringCandidatesComboBoxHandler::connectLineEdit() { QObject::connect(mLineEdit, &QLineEdit::textChanged, this, &QtnPropertyQStringCandidatesComboBoxHandler::updatePlaceholder); QObject::connect(mLineEdit, &QtnCompleterLineEdit::returnPressed, this, &QtnPropertyQStringCandidatesComboBoxHandler::onItemActivated); QObject::connect(mLineEdit, &QtnCompleterLineEdit::escaped, this, &QtnPropertyQStringCandidatesComboBoxHandler::revertInput); QObject::connect(mLineEdit, &QLineEdit::editingFinished, this, &QtnPropertyQStringCandidatesComboBoxHandler::onEditingFinished, Qt::QueuedConnection); QObject::connect(mLineEdit->completer(), static_cast( &QCompleter::activated), this, &QtnPropertyQStringCandidatesComboBoxHandler::onItemActivated); } void QtnPropertyQStringCandidatesComboBoxHandler::disconnectLineEdit() { QObject::disconnect(mLineEdit, &QtnCompleterLineEdit::returnPressed, this, &QtnPropertyQStringCandidatesComboBoxHandler::onItemActivated); QObject::disconnect(mLineEdit, &QtnCompleterLineEdit::escaped, this, &QtnPropertyQStringCandidatesComboBoxHandler::revertInput); QObject::disconnect(mLineEdit, &QLineEdit::editingFinished, this, &QtnPropertyQStringCandidatesComboBoxHandler::onEditingFinished); QObject::disconnect(mLineEdit->completer(), static_cast( &QCompleter::activated), this, &QtnPropertyQStringCandidatesComboBoxHandler::onItemActivated); } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateQString.h ================================================ /******************************************************************************* Copyright (c) 2012-2019 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_QSTRING_H #define PROPERTY_DELEGATE_QSTRING_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyQString.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateQString : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateQString) typedef QtnPropertyDelegateTyped Inherited; public: QtnPropertyDelegateQString(QtnPropertyQStringBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual bool acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; virtual bool isPlaceholderColor() const override; protected: int m_maxLength; bool m_multiline; QString m_placeholder; }; class QTN_IMPORT_EXPORT QtnPropertyDelegateQStringInvalidBase : public QtnPropertyDelegateQString { Q_DISABLE_COPY(QtnPropertyDelegateQStringInvalidBase) protected: QtnPropertyDelegateQStringInvalidBase(QtnPropertyQStringBase &owner); virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual void drawValueImpl( QStylePainter &painter, const QRect &rect) const override; virtual bool isPropertyValid() const = 0; private: QColor m_invalidColor; }; class QTN_IMPORT_EXPORT QtnPropertyDelegateQStringFile : public QtnPropertyDelegateQStringInvalidBase { Q_DISABLE_COPY(QtnPropertyDelegateQStringFile) public: QtnPropertyDelegateQStringFile(QtnPropertyQStringBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; virtual bool toolTipImpl(QString &strValue) const override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool isPropertyValid() const override; QString defaultDirectory() const; QString absoluteFilePath() const; QString relativeFilePath() const; bool shouldShowRelativePath() const; private: QtnPropertyDelegateInfo m_editorAttributes; }; class QTN_IMPORT_EXPORT QtnPropertyDelegateQStringList : public QtnPropertyDelegateQString { Q_DISABLE_COPY(QtnPropertyDelegateQStringList) public: QtnPropertyDelegateQStringList(QtnPropertyQStringBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; private: QtnPropertyDelegateInfo m_editorAttributes; }; using QtnGetCandidatesFn = std::function; using QtnCreateCandidateFn = std::function; Q_DECLARE_METATYPE(QtnGetCandidatesFn); Q_DECLARE_METATYPE(QtnCreateCandidateFn); class QtnPropertyQStringCandidatesComboBoxHandler; class QTN_IMPORT_EXPORT QtnPropertyDelegateQStringCallback : public QtnPropertyDelegateQString { Q_DISABLE_COPY(QtnPropertyDelegateQStringCallback) public: QtnPropertyDelegateQStringCallback(QtnPropertyQStringBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; private: QtnPropertyDelegateInfo m_editorAttributes; friend class QtnPropertyQStringCandidatesComboBoxHandler; }; #endif // PROPERTY_DELEGATE_QSTRING_H ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateUInt.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateUInt.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/Delegates/Utils/PropertyDelegateSliderBox.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Utils/QtnInt64SpinBox.h" #include "QtnProperty/MultiProperty.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include #include class QtnPropertyUIntSpinBoxHandler : public QtnPropertyEditorHandlerVT { public: QtnPropertyUIntSpinBoxHandler( QtnPropertyDelegateUInt *delegate, QtnInt64SpinBox &editor); protected: virtual void updateEditor() override; void onValueChanged(qint64 value); private: QtnPropertyDelegateUInt *m_delegate; }; QtnPropertyDelegateUInt::QtnPropertyDelegateUInt(QtnPropertyUIntBase &owner) : QtnPropertyDelegateTyped(owner) { } void QtnPropertyDelegateUInt::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyUIntBase::staticMetaObject, &qtnCreateDelegate, qtnSpinBoxDelegate()); factory.registerDelegate(&QtnPropertyUIntBase::staticMetaObject, &qtnCreateDelegate< QtnPropertyDelegateSlideBoxTyped, QtnPropertyUIntBase>, qtnSliderBoxDelegate()); } uint QtnPropertyDelegateUInt::stepValue() const { return m_step.isValid() ? m_step.toUInt() : owner().stepValue(); } uint QtnPropertyDelegateUInt::minValue() const { return m_min.isValid() ? m_min.toUInt() : owner().minValue(); } uint QtnPropertyDelegateUInt::maxValue() const { return m_max.isValid() ? m_max.toUInt() : owner().maxValue(); } uint QtnPropertyDelegateUInt::currentValue() const { return qBound(minValue(), owner().value(), maxValue()); } QWidget *QtnPropertyDelegateUInt::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { auto spinBox = new QtnInt64SpinBox(parent); spinBox->setSuffix(m_suffix); spinBox->setGeometry(rect); new QtnPropertyUIntSpinBoxHandler(this, *spinBox); spinBox->selectAll(); if (stateProperty()->isEditableByUser()) qtnInitNumEdit(spinBox, inplaceInfo, NUM_UNSIGNED_INT); return spinBox; } bool QtnPropertyDelegateUInt::acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const { if (QtnPropertyDelegateTyped< QtnPropertyUIntBase>::acceptKeyPressedForInplaceEditImpl(keyEvent)) return true; return qtnAcceptForNumEdit(keyEvent, NUM_UNSIGNED_INT); } void QtnPropertyDelegateUInt::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnSuffixAttr(), m_suffix); m_min = info.attributes.value(qtnMinAttr()); m_max = info.attributes.value(qtnMaxAttr()); m_step = info.attributes.value(qtnStepAttr()); if (m_step.isValid()) { bool ok; uint step = m_step.toUInt(&ok); if (!ok) { m_step = QVariant(); } else { m_step = step; } } fixMinMaxVariant(m_min, m_max); } bool QtnPropertyDelegateUInt::propertyValueToStrImpl(QString &strValue) const { strValue = QLocale().toString(currentValue()); strValue.append(m_suffix); return true; } QtnPropertyUIntSpinBoxHandler::QtnPropertyUIntSpinBoxHandler( QtnPropertyDelegateUInt *delegate, QtnInt64SpinBox &editor) : QtnPropertyEditorHandlerVT(delegate, editor) , m_delegate(delegate) { updateEditor(); editor.setKeyboardTracking(false); editor.installEventFilter(this); QObject::connect(&editor, static_cast( &QtnInt64SpinBox::valueChanged), this, &QtnPropertyUIntSpinBoxHandler::onValueChanged); } void QtnPropertyUIntSpinBoxHandler::updateEditor() { updating++; editor().setReadOnly(!stateProperty()->isEditableByUser()); editor().setSingleStep(m_delegate->stepValue()); editor().setRange(m_delegate->minValue(), m_delegate->maxValue()); if (stateProperty()->isMultiValue()) { editor().setValue(editor().minimum()); editor().setSpecialValueText( QtnMultiProperty::getMultiValuePlaceholder()); } else { editor().setValue(m_delegate->currentValue()); editor().setSpecialValueText(QString()); } editor().selectAll(); updating--; } void QtnPropertyUIntSpinBoxHandler::onValueChanged(qint64 value) { QtnPropertyEditorHandlerVT::onValueChanged(ValueTypeStore(value)); } ================================================ FILE: QtnProperty/Delegates/Core/PropertyDelegateUInt.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_UINT_H #define PROPERTY_DELEGATE_UINT_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyUInt.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateUInt : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateUInt) QString m_suffix; QVariant m_min; QVariant m_max; QVariant m_step; public: QtnPropertyDelegateUInt(QtnPropertyUIntBase &owner); static void Register(QtnPropertyDelegateFactory &factory); uint stepValue() const; uint minValue() const; uint maxValue() const; uint currentValue() const; protected: virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const override; virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; #endif // PROPERTY_DELEGATE_UINT_H ================================================ FILE: QtnProperty/Delegates/GUI/PropertyDelegateButton.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateButton.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/PropertyView.h" #include "QtnProperty/GUI/PropertyButton.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include #include QByteArray qtnLinkDelegateName() { return QByteArrayLiteral("Link"); } QByteArray qtnTitleAttr() { return QByteArrayLiteral("title"); } void QtnPropertyDelegateButton::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyButton::staticMetaObject, &qtnCreateDelegate, "Button"); } void QtnPropertyDelegateButtonLink::Register( QtnPropertyDelegateFactory &factory) { factory.registerDelegate(&QtnPropertyButton::staticMetaObject, &qtnCreateDelegate, qtnLinkDelegateName()); } QtnPropertyDelegateButton::QtnPropertyDelegateButton(QtnPropertyButton &owner) : QtnPropertyDelegateTyped(owner) { m_title = owner.displayName(); } void QtnPropertyDelegateButton::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnTitleAttr(), m_title); } void QtnPropertyDelegateButton::createSubItemsImpl( QtnDrawContext &context, QList &subItems) { QtnSubItem buttonItem(context.rect); buttonItem.trackState(); buttonItem.setPropertyDescriptionAsTooltip(owner()); buttonItem.drawHandler = [this](QtnDrawContext &context, const QtnSubItem &item) { auto style = context.style(); QStyleOptionButton option; context.initStyleOption(option); option.state = state(context.isActive, item); if (0 == (option.state & QStyle::State_Sunken)) { option.state |= QStyle::State_Raised; } #ifdef Q_OS_MAC option.state &= ~QStyle::State_MouseOver; option.features = QStyleOptionButton::Flat; #endif // dont initialize styleObject from widget for QWindowsVistaStyle // this disables buggous animations if (style->inherits("QWindowsVistaStyle")) option.styleObject = nullptr; option.rect = item.rect; option.text = m_title; owner().invokePreDrawButton(&option); // draw button style->drawControl( QStyle::CE_PushButton, &option, context.painter, context.widget); }; buttonItem.eventHandler = [this](QtnEventContext &context, const QtnSubItem &, QtnPropertyToEdit *) -> bool { bool doClick = false; switch (context.eventType()) { case QtnSubItemEvent::ReleaseMouse: doClick = true; break; case QEvent::KeyPress: int key = context.eventAs()->key(); doClick = (key == Qt::Key_Space) || (key == Qt::Key_Return); break; } if (doClick) { owner().invokeClick(); return true; } return false; }; subItems.append(buttonItem); } QtnPropertyDelegateButtonLink::QtnPropertyDelegateButtonLink( QtnPropertyButton &owner) : QtnPropertyDelegateButton(owner) { } void QtnPropertyDelegateButtonLink::createSubItemsImpl( QtnDrawContext &context, QList &subItems) { QtnSubItem linkItem(context.rect.marginsRemoved(context.margins)); linkItem.rect.setWidth(context.painter->fontMetrics().width(m_title)); linkItem.setPropertyDescriptionAsTooltip(owner()); linkItem.trackState(); linkItem.drawHandler = [this](QtnDrawContext &context, const QtnSubItem &item) { context.painter->save(); QColor linkColor = context.palette().color(context.colorGroup(), context.isActive ? QPalette::HighlightedText : QPalette::Link); switch (item.state()) { case QtnSubItemStateUnderCursor: { auto font = context.painter->font(); font.setUnderline(true); context.painter->setFont(font); break; } case QtnSubItemStatePushed: { auto font = context.painter->font(); font.setUnderline(true); context.painter->setFont(font); break; } default: break; } if (context.isActive) { context.painter->fillRect( context.rect, context.palette().color(QPalette::Highlight)); } context.painter->setPen(linkColor); context.painter->drawText( item.rect, Qt::AlignLeading | Qt::AlignVCenter, m_title); context.painter->restore(); }; linkItem.eventHandler = [this](QtnEventContext &context, const QtnSubItem &, QtnPropertyToEdit *) -> bool { bool doClick = false; switch (context.eventType()) { case QEvent::KeyPress: { int key = context.eventAs()->key(); doClick = (key == Qt::Key_Space) || (key == Qt::Key_Return); break; } case QtnSubItemEvent::Activated: { m_widgetCursor = context.widget->cursor(); context.widget->setCursor(Qt::PointingHandCursor); break; } case QtnSubItemEvent::Deactivated: { context.widget->setCursor(m_widgetCursor); break; } case QtnSubItemEvent::ReleaseMouse: { doClick = true; break; } } if (doClick) { owner().invokeClick(); return true; } return false; }; subItems.append(linkItem); } ================================================ FILE: QtnProperty/Delegates/GUI/PropertyDelegateButton.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_BUTTON_H #define PROPERTY_DELEGATE_BUTTON_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/GUI/PropertyButton.h" class QtnPropertyButton; class QTN_IMPORT_EXPORT QtnPropertyDelegateButton : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateButton) public: QtnPropertyDelegateButton(QtnPropertyButton &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: void applyAttributesImpl(const QtnPropertyDelegateInfo &info) override; void createSubItemsImpl( QtnDrawContext &context, QList &subItems) override; QString m_title; }; class QTN_IMPORT_EXPORT QtnPropertyDelegateButtonLink : public QtnPropertyDelegateButton { Q_DISABLE_COPY(QtnPropertyDelegateButtonLink) public: QtnPropertyDelegateButtonLink(QtnPropertyButton &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: void createSubItemsImpl( QtnDrawContext &context, QList &subItems) override; private: QCursor m_widgetCursor; }; #endif // PROPERTY_DELEGATE_BUTTON_H ================================================ FILE: QtnProperty/Delegates/GUI/PropertyDelegateQBrush.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateQBrush.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include #include #include QByteArray qtnShowAllAttr() { return QByteArrayLiteral("showAll"); } void QtnPropertyDelegateQBrushStyle::Register( QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault( &QtnPropertyQBrushStyleBase::staticMetaObject, &qtnCreateDelegate, qtnComboBoxDelegate()); } static void drawBrushStyle( QStyle *style, QPainter &painter, QRect rect, Qt::BrushStyle brushStyle) { switch (brushStyle) { case Qt::NoBrush: case Qt::LinearGradientPattern: case Qt::RadialGradientPattern: case Qt::ConicalGradientPattern: case Qt::TexturePattern: { QString str; QtnPropertyQBrushStyle::translateBrushStyle(brushStyle, str); qtnDrawValueText(str, painter, rect, style); break; } default: { rect.adjust(2, 2, -2, -2); auto brush = painter.brush(); brush.setStyle(brushStyle); auto oldBrush = painter.brush(); painter.setBrush(brush); painter.drawRect(rect); painter.setBrush(oldBrush); } } } class QtnPropertyBrushStyleItemDelegate : public QStyledItemDelegate { QComboBox *m_owner; public: QtnPropertyBrushStyleItemDelegate(QComboBox *owner); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; class QtnPropertyBrushStyleComboBox : public QtnPropertyComboBox { public: explicit QtnPropertyBrushStyleComboBox( QtnPropertyDelegate *delegate, QWidget *parent = Q_NULLPTR); protected: virtual void customPaint(QPainter &painter, const QRect &rect) override; }; class QtnPropertyBrushStyleComboBoxHandler : public QtnPropertyEditorHandlerVT { public: QtnPropertyBrushStyleComboBoxHandler( QtnPropertyDelegate *delegate, QComboBox &editor); private: void updateEditor() override; void onCurrentIndexChanged(int index); }; QtnPropertyDelegateQBrushStyle::QtnPropertyDelegateQBrushStyle( QtnPropertyQBrushStyleBase &owner) : QtnPropertyDelegateTyped(owner) , m_showAll(false) { } void QtnPropertyDelegateQBrushStyle::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnShowAllAttr(), m_showAll); } void QtnPropertyDelegateQBrushStyle::drawValueImpl( QStylePainter &painter, const QRect &rect) const { if (stateProperty()->isMultiValue()) { QtnPropertyDelegateTyped::drawValueImpl(painter, rect); } else { auto value = owner().value(); drawBrushStyle(painter.style(), painter, rect, value); } } QWidget *QtnPropertyDelegateQBrushStyle::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { if (stateProperty()->isEditableByUser()) { QComboBox *combo = new QtnPropertyBrushStyleComboBox(this, parent); combo->setLineEdit(nullptr); combo->setItemDelegate(new QtnPropertyBrushStyleItemDelegate(combo)); if (m_showAll) { for (auto bs = Qt::NoBrush; bs <= Qt::ConicalGradientPattern; bs = Qt::BrushStyle(bs + 1)) { combo->addItem(QString(), QVariant::fromValue(bs)); } combo->addItem(QString(), QVariant::fromValue(Qt::TexturePattern)); } else { combo->addItem(QString(), QVariant::fromValue(Qt::NoBrush)); combo->addItem(QString(), QVariant::fromValue(Qt::SolidPattern)); combo->addItem(QString(), QVariant::fromValue(Qt::HorPattern)); combo->addItem(QString(), QVariant::fromValue(Qt::VerPattern)); combo->addItem(QString(), QVariant::fromValue(Qt::CrossPattern)); combo->addItem(QString(), QVariant::fromValue(Qt::BDiagPattern)); combo->addItem(QString(), QVariant::fromValue(Qt::FDiagPattern)); combo->addItem( QString(), QVariant::fromValue(Qt::DiagCrossPattern)); } combo->setGeometry(rect); new QtnPropertyBrushStyleComboBoxHandler(this, *combo); if (inplaceInfo && stateProperty()->isEditableByUser()) combo->showPopup(); return combo; } return nullptr; } bool QtnPropertyDelegateQBrushStyle::propertyValueToStrImpl( QString &strValue) const { return QtnPropertyQBrushStyle::translateBrushStyle( owner().value(), strValue); } QtnPropertyBrushStyleComboBoxHandler::QtnPropertyBrushStyleComboBoxHandler( QtnPropertyDelegate *delegate, QComboBox &editor) : QtnPropertyEditorHandlerVT(delegate, editor) { updateEditor(); QObject::connect(&editor, static_cast(&QComboBox::currentIndexChanged), this, &QtnPropertyBrushStyleComboBoxHandler::onCurrentIndexChanged); } void QtnPropertyBrushStyleComboBoxHandler::updateEditor() { updating++; if (stateProperty()->isMultiValue()) editor().setCurrentIndex(-1); else { int index = editor().findData(QVariant::fromValue(property().value())); editor().setCurrentIndex(index); } updating--; } void QtnPropertyBrushStyleComboBoxHandler::onCurrentIndexChanged(int index) { if (index >= 0) { QVariant data = editor().itemData(index); if (data.canConvert()) onValueChanged(data.value()); } } QtnPropertyBrushStyleComboBox::QtnPropertyBrushStyleComboBox( QtnPropertyDelegate *delegate, QWidget *parent) : QtnPropertyComboBox(delegate, parent) { } void QtnPropertyBrushStyleComboBox::customPaint( QPainter &painter, const QRect &rect) { auto brushStyle = currentData().value(); drawBrushStyle(style(), painter, rect, brushStyle); } QtnPropertyBrushStyleItemDelegate::QtnPropertyBrushStyleItemDelegate( QComboBox *owner) : m_owner(owner) { } void QtnPropertyBrushStyleItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyledItemDelegate::paint(painter, option, index); auto brushStyle = index.data(Qt::UserRole).value(); drawBrushStyle(m_owner->style(), *painter, option.rect, brushStyle); } ================================================ FILE: QtnProperty/Delegates/GUI/PropertyDelegateQBrush.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_QBRUSH_H #define PROPERTY_DELEGATE_QBRUSH_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/GUI/PropertyQBrush.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateQBrushStyle : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateQBrushStyle) public: QtnPropertyDelegateQBrushStyle(QtnPropertyQBrushStyleBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual void drawValueImpl( QStylePainter &painter, const QRect &rect) const override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; private: bool m_showAll; }; #endif // PROPERTY_DELEGATE_QBRUSH_H ================================================ FILE: QtnProperty/Delegates/GUI/PropertyDelegateQColor.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateQColor.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include "QtnProperty/Utils/InplaceEditing.h" #include QByteArray qtnShapeAttr() { return QByteArrayLiteral("shape"); } QByteArray qtnRgbSubItemsAttr() { return QByteArrayLiteral("rgbSubItems"); } QByteArray qtnSolidDelegateName() { return QByteArrayLiteral("Solid"); } QByteArray qtnSelectColorDelegateName() { return QByteArrayLiteral("SelectColor"); } class QtnPropertyQColorLineEditBttnHandler : public QtnPropertyEditorBttnHandler { public: QtnPropertyQColorLineEditBttnHandler( QtnPropertyDelegate *delegate, QtnLineEditBttn &editor); protected: virtual void onToolButtonClick() override; virtual void updateEditor() override; private: void onToolButtonClicked(bool); void onEditingFinished(); }; QtnPropertyDelegateQColor::QtnPropertyDelegateQColor( QtnPropertyQColorBase &owner) : QtnPropertyDelegateTypedEx(owner) , m_shape(QtnColorDelegateShapeSquare) { } void QtnPropertyDelegateQColor::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyQColorBase::staticMetaObject, &qtnCreateDelegate, qtnSelectColorDelegateName()); } void QtnPropertyDelegateQColor::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnShapeAttr(), m_shape); if (info.getAttribute(qtnRgbSubItemsAttr(), false)) { addSubProperty(owner().createRedProperty()); addSubProperty(owner().createGreenProperty()); addSubProperty(owner().createBlueProperty()); } } void QtnPropertyDelegateQColor::drawValueImpl( QStylePainter &painter, const QRect &rect) const { if (stateProperty()->isMultiValue()) { QtnPropertyDelegateTypedEx::drawValueImpl(painter, rect); return; } QColor value = owner().value(); QRect textRect = rect; if (m_shape != QtnColorDelegateShapeNone) { QRect colorRect = rect; colorRect.setWidth(colorRect.height()); colorRect.adjust(2, 2, -2, -2); if (m_shape == QtnColorDelegateShapeSquare) { painter.fillRect(colorRect, painter.style()->standardPalette().color( stateProperty()->isEditableByUser() ? QPalette::Active : QPalette::Disabled, QPalette::Text)); colorRect.adjust(1, 1, -1, -1); painter.fillRect(colorRect, value); } else if (m_shape == QtnColorDelegateShapeCircle) { auto oldBrush = painter.brush(); bool oldAntiAliasing = painter.testRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::Antialiasing); painter.setBrush(value); painter.drawEllipse(colorRect); painter.setRenderHint(QPainter::Antialiasing, oldAntiAliasing); painter.setBrush(oldBrush); } textRect.setLeft(colorRect.right() + 3); } if (textRect.isValid()) { QtnPropertyDelegateTyped::drawValueImpl( painter, textRect); } } QWidget *QtnPropertyDelegateQColor::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { QtnLineEditBttn *editor = new QtnLineEditBttn(parent); editor->setGeometry(rect); new QtnPropertyQColorLineEditBttnHandler(this, *editor); if (inplaceInfo) { editor->lineEdit->selectAll(); } return editor; } bool QtnPropertyDelegateQColor::propertyValueToStrImpl(QString &strValue) const { return owner().toStr(strValue); } QtnPropertyDelegateQColorSolid::QtnPropertyDelegateQColorSolid( QtnPropertyQColorBase &owner) : QtnPropertyDelegateTyped(owner) { } void QtnPropertyDelegateQColorSolid::Register( QtnPropertyDelegateFactory &factory) { factory.registerDelegate(&QtnPropertyQColorBase::staticMetaObject, &qtnCreateDelegate, qtnSolidDelegateName()); } bool QtnPropertyDelegateQColorSolid::createSubItemValueImpl( QtnDrawContext &context, QtnSubItem &subItemValue) { if (!QtnPropertyDelegateTyped< QtnPropertyQColorBase>::createSubItemValueImpl(context, subItemValue)) return false; // correct left value rect subItemValue.rect.setLeft(context.splitPos); return true; } void QtnPropertyDelegateQColorSolid::drawValueImpl( QStylePainter &painter, const QRect &rect) const { if (stateProperty()->isMultiValue()) { QtnPropertyDelegateTyped::drawValueImpl(painter, rect); return; } auto boxRect = rect; boxRect.adjust(2, 2, -2, -2); painter.fillRect(boxRect, owner()); } QWidget *QtnPropertyDelegateQColorSolid::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { Q_UNUSED(rect); Q_UNUSED(inplaceInfo); QColorDialog dlg(owner(), parent); if (dlg.exec() == QDialog::Accepted) { owner().setValue(dlg.currentColor(), editReason()); } return nullptr; } QtnPropertyQColorLineEditBttnHandler::QtnPropertyQColorLineEditBttnHandler( QtnPropertyDelegate *delegate, QtnLineEditBttn &editor) : QtnPropertyEditorHandlerType(delegate, editor) { if (!stateProperty()->isEditableByUser()) { editor.lineEdit->setReadOnly(true); editor.toolButton->setEnabled(false); } QtnPropertyQColorLineEditBttnHandler::updateEditor(); editor.lineEdit->installEventFilter(this); QObject::connect(editor.toolButton, &QToolButton::clicked, this, &QtnPropertyQColorLineEditBttnHandler::onToolButtonClicked); QObject::connect(editor.lineEdit, &QLineEdit::editingFinished, this, &QtnPropertyQColorLineEditBttnHandler::onEditingFinished); } void QtnPropertyQColorLineEditBttnHandler::onToolButtonClick() { onToolButtonClicked(false); } void QtnPropertyQColorLineEditBttnHandler::updateEditor() { QString str; property().toStr(str); editor().setTextForProperty(stateProperty(), str); editor().lineEdit->selectAll(); } void QtnPropertyQColorLineEditBttnHandler::onToolButtonClicked(bool) { auto property = &this->property(); volatile bool destroyed = false; auto connection = QObject::connect(property, &QObject::destroyed, [&destroyed]() mutable { destroyed = true; }); reverted = true; auto dialog = new QColorDialog(property->value(), editorBase()); auto dialogContainer = connectDialog(dialog); if (dialog->exec() == QDialog::Accepted && !destroyed) { property->setValue(dialog->currentColor(), delegate()->editReason()); } if (!destroyed) QObject::disconnect(connection); Q_UNUSED(dialogContainer); } void QtnPropertyQColorLineEditBttnHandler::onEditingFinished() { if (canApply()) { property().fromStr(editor().lineEdit->text(), delegate()->editReason()); } applyReset(); } ================================================ FILE: QtnProperty/Delegates/GUI/PropertyDelegateQColor.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_QCOLOR_H #define PROPERTY_DELEGATE_QCOLOR_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/GUI/PropertyQColor.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateQColor : public QtnPropertyDelegateTypedEx { Q_DISABLE_COPY(QtnPropertyDelegateQColor) public: QtnPropertyDelegateQColor(QtnPropertyQColorBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual void drawValueImpl( QStylePainter &painter, const QRect &rect) const override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; private: quint32 m_shape; }; class QTN_IMPORT_EXPORT QtnPropertyDelegateQColorSolid : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateQColorSolid) public: QtnPropertyDelegateQColorSolid(QtnPropertyQColorBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual bool createSubItemValueImpl( QtnDrawContext &context, QtnSubItem &subItemValue) override; virtual void drawValueImpl( QStylePainter &painter, const QRect &rect) const override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; }; #endif // PROPERTY_DELEGATE_QCOLOR_H ================================================ FILE: QtnProperty/Delegates/GUI/PropertyDelegateQFont.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateQFont.h" #include "QtnProperty/Core/PropertyQString.h" #include "QtnProperty/Core/PropertyInt.h" #include "QtnProperty/Core/PropertyBool.h" #include "QtnProperty/Core/PropertyEnum.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include "QtnProperty/PropertySet.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include #include QByteArray qtnSelectFontDelegate() { return QByteArrayLiteral("SelectFont"); } class QtnPropertyQFontLineEditBttnHandler : public QtnPropertyEditorBttnHandler { public: QtnPropertyQFontLineEditBttnHandler( QtnPropertyDelegate *delegate, QtnLineEditBttn &editor); protected: virtual void onToolButtonClick() override; virtual void updateEditor() override; private: void onToolButtonClicked(bool); }; static const QtnEnumInfo *styleStrategyEnum() { static QScopedPointer enumInfo; if (nullptr == enumInfo) { QVector items; items.append(QtnEnumValueInfo(QFont::PreferDefault, "PreferDefault", QtnPropertyQFont::getPreferDefaultStr())); items.append(QtnEnumValueInfo(QFont::NoAntialias, "NoAntialias", QtnPropertyQFont::getNoAntialiasStr())); items.append(QtnEnumValueInfo(QFont::PreferAntialias, "PreferAntialias", QtnPropertyQFont::getPreferAntialiasStr())); enumInfo.reset(new QtnEnumInfo("FontStyleStrategy", items)); } return enumInfo.data(); } enum { SizeUnitPixel, SizeUnitPoint }; static const QtnEnumInfo *sizeUnitEnum() { static QScopedPointer enumInfo; if (nullptr == enumInfo) { QVector items; items.append(QtnEnumValueInfo( SizeUnitPixel, "Pixel", QtnPropertyQFont::getPixelStr())); items.append(QtnEnumValueInfo( SizeUnitPoint, "Point", QtnPropertyQFont::getPointStr())); enumInfo.reset(new QtnEnumInfo("FontSizeUnit", items)); } return enumInfo.data(); } static void applyFontStyle(QFont &font) { #ifdef Q_OS_MAC auto style = font.styleName(); if (!style.isEmpty()) { auto family = font.family(); QFontDatabase db; for (const auto &s : db.styles(family)) { if (s == style) { font.setBold(db.bold(family, style)); font.setItalic(db.italic(family, style)); return; } } } #else Q_UNUSED(font); #endif } QtnPropertyDelegateQFont::QtnPropertyDelegateQFont(QtnPropertyQFontBase &owner) : QtnPropertyDelegateTypedEx(owner) { auto propertyStyle = new QtnPropertyQStringCallback; auto propertyFamily = new QtnPropertyQStringCallback; addSubProperty(propertyFamily); propertyFamily->setName(QStringLiteral("family")); propertyFamily->setDisplayName(QtnPropertyQFont::getFamilyLabel()); propertyFamily->setDescription( QtnPropertyQFont::getFamilyDescription(owner.name())); propertyFamily->setCallbackValueGet( [&owner]() -> QString { return owner.value().family(); }); propertyFamily->setCallbackValueSet([&owner, propertyStyle](QString value, QtnPropertyChangeReason reason) { QFont font = owner.value(); font.setFamily(value); applyFontStyle(font); owner.setValue(font, reason); #ifdef Q_OS_MAC QtnPropertyDelegateInfo delegate; delegate.name = qtnComboBoxDelegate(); QFontDatabase fDB; delegate.attributes[qtnItemsAttr()] = QStringList(QString()) + fDB.styles(value); delegate.attributes[qtnEditableAttr()] = true; propertyStyle->setDelegateInfo(delegate); owner.postUpdateEvent(QtnPropertyChangeReasonChildren); #else Q_UNUSED(propertyStyle); #endif }); QtnPropertyDelegateInfo delegate; delegate.name = qtnComboBoxDelegate(); QFontDatabase fDB; delegate.attributes[qtnItemsAttr()] = fDB.families(); propertyFamily->setDelegateInfo(delegate); propertyStyle->setName(QStringLiteral("style")); propertyStyle->setDisplayName(QtnPropertyQFont::getStyleLabel()); propertyStyle->setDescription( QtnPropertyQFont::getStyleDescription(owner.name())); propertyStyle->setCallbackValueGet( [&owner]() -> QString { return owner.value().styleName(); }); propertyStyle->setCallbackValueSet([&owner](QString value, QtnPropertyChangeReason reason) { QFont font = owner.value(); font.setStyleName(value); applyFontStyle(font); owner.setValue(font, reason); }); #ifdef Q_OS_MAC delegate.name = qtnComboBoxDelegate(); delegate.attributes[qtnItemsAttr()] = QStringList(QString()) + fDB.styles(owner.value().family()); delegate.attributes[qtnEditableAttr()] = true; #else delegate.name = qtnLineEditDelegate(); delegate.attributes[qtnMultiLineEditAttr()] = false; #endif propertyStyle->setDelegateInfo(delegate); addSubProperty(propertyStyle); auto propertySize = new QtnPropertyIntCallback; addSubProperty(propertySize); propertySize->setName(QStringLiteral("size")); propertySize->setDisplayName(QtnPropertyQFont::getSizeLabel()); propertySize->setDescription( QtnPropertyQFont::getSizeDescription(owner.name())); propertySize->setCallbackValueGet([&owner]() -> qint32 { int ps = owner.value().pointSize(); if (ps < 0) ps = owner.value().pixelSize(); if (ps <= 0) ps = 1; if (ps > 256) ps = 256; return ps; }); propertySize->setCallbackValueSet([&owner](qint32 value, QtnPropertyChangeReason reason) { if (value <= 0) value = 1; else if (value > 256) value = 256; QFont font = owner.value(); if (font.pointSize() > 0) { font.setPointSize(value); } else { font.setPixelSize(value); } owner.setValue(font, reason); }); propertySize->setMinValue(1); propertySize->setMaxValue(256); QtnPropertyEnumCallback *propertySizeUnit = new QtnPropertyEnumCallback; addSubProperty(propertySizeUnit); propertySizeUnit->setName(QStringLiteral("sizeUnit")); propertySizeUnit->setDisplayName(QtnPropertyQFont::getSizeUnitLabel()); propertySizeUnit->setDescription( QtnPropertyQFont::getSizeUnitDescription(owner.name())); propertySizeUnit->setEnumInfo(sizeUnitEnum()); propertySizeUnit->setCallbackValueGet([&owner]() -> QtnEnumValueType { if (owner.value().pointSize() < 0) return SizeUnitPixel; return SizeUnitPoint; }); propertySizeUnit->setCallbackValueSet([&owner](QtnEnumValueType value, QtnPropertyChangeReason reason) { QFont font = owner.value(); int size = std::max(font.pointSize(), font.pixelSize()); if (size <= 0) size = 1; if (size > 256) size = 256; switch (value) { case SizeUnitPixel: font.setPixelSize(size); break; case SizeUnitPoint: font.setPointSize(size); break; default: break; } owner.setValue(font, reason); }); QtnPropertyBoolCallback *propertyBold = new QtnPropertyBoolCallback; addSubProperty(propertyBold); propertyBold->setName(QStringLiteral("bold")); propertyBold->setDisplayName(QtnPropertyQFont::getBoldLabel()); propertyBold->setDescription( QtnPropertyQFont::getBoldDescription(owner.name())); propertyBold->setCallbackValueGet( [&owner]() -> bool { return owner.value().bold(); }); propertyBold->setCallbackValueSet([&owner](bool value, QtnPropertyChangeReason reason) { QFont font = owner.value(); if (font.bold() != value) { #ifdef Q_OS_MAC auto style = font.styleName(); if (!style.isEmpty()) { auto family = font.family(); QFontDatabase db; for (auto &s : db.styles(family)) { if (s == style) { if (value != db.bold(family, style)) return; break; } } } #endif font.setBold(value); owner.setValue(font, reason); } }); QtnPropertyBoolCallback *propertyItalic = new QtnPropertyBoolCallback; addSubProperty(propertyItalic); propertyItalic->setName(QStringLiteral("italic")); propertyItalic->setDisplayName(QtnPropertyQFont::getItalicLabel()); propertyItalic->setDescription( QtnPropertyQFont::getItalicDescription(owner.name())); propertyItalic->setCallbackValueGet( [&owner]() -> bool { return owner.value().italic(); }); propertyItalic->setCallbackValueSet([&owner](bool value, QtnPropertyChangeReason reason) { QFont font = owner.value(); if (font.italic() != value) { #ifdef Q_OS_MAC auto style = font.styleName(); if (!style.isEmpty()) { auto family = font.family(); QFontDatabase db; for (auto &s : db.styles(family)) { if (s == style) { if (value != db.italic(family, style)) return; break; } } } #endif font.setItalic(value); owner.setValue(font, reason); } }); QtnPropertyBoolCallback *propertyUnderline = new QtnPropertyBoolCallback; addSubProperty(propertyUnderline); propertyUnderline->setName(QStringLiteral("underline")); propertyUnderline->setDisplayName(QtnPropertyQFont::getUnderlineLabel()); propertyUnderline->setDescription( QtnPropertyQFont::getUnderlineDescription(owner.name())); propertyUnderline->setCallbackValueGet( [&owner]() -> bool { return owner.value().underline(); }); propertyUnderline->setCallbackValueSet([&owner](bool value, QtnPropertyChangeReason reason) { QFont font = owner.value(); font.setUnderline(value); owner.setValue(font, reason); }); QtnPropertyBoolCallback *propertyStrikeout = new QtnPropertyBoolCallback; addSubProperty(propertyStrikeout); propertyStrikeout->setName(QStringLiteral("strikeout")); propertyStrikeout->setDisplayName(QtnPropertyQFont::getStrikeoutLabel()); propertyStrikeout->setDescription( QtnPropertyQFont::getStrikeoutDescription(owner.name())); propertyStrikeout->setCallbackValueGet( [&owner]() -> bool { return owner.value().strikeOut(); }); propertyStrikeout->setCallbackValueSet([&owner](bool value, QtnPropertyChangeReason reason) { QFont font = owner.value(); font.setStrikeOut(value); owner.setValue(font, reason); }); QtnPropertyBoolCallback *propertyKerning = new QtnPropertyBoolCallback; addSubProperty(propertyKerning); propertyKerning->setName(QStringLiteral("kerning")); propertyKerning->setDisplayName(QtnPropertyQFont::getKerningLabel()); propertyKerning->setDescription( QtnPropertyQFont::getKerningDescription(owner.name())); propertyKerning->setCallbackValueGet( [&owner]() -> bool { return owner.value().kerning(); }); propertyKerning->setCallbackValueSet([&owner](bool value, QtnPropertyChangeReason reason) { QFont font = owner.value(); font.setKerning(value); owner.setValue(font, reason); }); auto propertyAntialiasing = new QtnPropertyEnumCallback(nullptr); addSubProperty(propertyAntialiasing); propertyAntialiasing->setName(QStringLiteral("antialiasing")); propertyAntialiasing->setDisplayName( QtnPropertyQFont::getAntialiasingLabel()); propertyAntialiasing->setDescription( QtnPropertyQFont::getAntialiasingDescription(owner.name())); propertyAntialiasing->setEnumInfo(styleStrategyEnum()); propertyAntialiasing->setCallbackValueGet([&owner]() -> QtnEnumValueType { return owner.value().styleStrategy(); }); propertyAntialiasing->setCallbackValueSet([&owner](QtnEnumValueType value, QtnPropertyChangeReason reason) { QFont font = owner.value(); font.setStyleStrategy(static_cast(value)); owner.setValue(font, reason); }); } void QtnPropertyDelegateQFont::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyQFontBase::staticMetaObject, &qtnCreateDelegate, qtnSelectFontDelegate()); } QString QtnPropertyDelegateQFont::fontToStrWithFormat( const QFont &font, const QString &format) { return QString(format).arg(fontToStr(font)); } QString QtnPropertyDelegateQFont::fontToStr(const QFont &font) { int size = font.pointSize(); bool pixels = (size < 0); if (pixels) size = font.pixelSize(); return QString("%1, %2 %3") .arg(font.family(), QString::number(size), QString(pixels ? "px" : "pt")); } void QtnPropertyDelegateQFont::drawValueImpl( QStylePainter &painter, const QRect &rect) const { if (stateProperty()->isMultiValue()) { QtnPropertyDelegateTypedEx::drawValueImpl(painter, rect); return; } QFont value = owner().value(); QRect textRect = rect; if (textRect.isValid()) { QRect br; QFont oldFont = painter.font(); QFont newFont(value); newFont.setPointSize(oldFont.pointSize()); painter.setFont(newFont); painter.drawText( textRect, Qt::AlignLeading | Qt::AlignVCenter, "A", &br); painter.setFont(oldFont); textRect.setLeft(br.right() + 3); } if (textRect.isValid()) { QtnPropertyDelegateTypedEx::drawValueImpl( painter, textRect); } } QWidget *QtnPropertyDelegateQFont::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { QtnLineEditBttn *editor = new QtnLineEditBttn(parent); editor->setGeometry(rect); new QtnPropertyQFontLineEditBttnHandler(this, *editor); if (inplaceInfo) { editor->lineEdit->selectAll(); } return editor; } bool QtnPropertyDelegateQFont::propertyValueToStrImpl(QString &strValue) const { strValue = fontToStrWithFormat(owner().value()); return true; } QtnPropertyQFontLineEditBttnHandler::QtnPropertyQFontLineEditBttnHandler( QtnPropertyDelegate *delegate, QtnLineEditBttn &editor) : QtnPropertyEditorHandlerType(delegate, editor) { editor.lineEdit->setReadOnly(true); if (!stateProperty()->isEditableByUser()) { editor.toolButton->setEnabled(false); } updateEditor(); editor.lineEdit->installEventFilter(this); QObject::connect(editor.toolButton, &QToolButton::clicked, this, &QtnPropertyQFontLineEditBttnHandler::onToolButtonClicked); } void QtnPropertyQFontLineEditBttnHandler::onToolButtonClick() { onToolButtonClicked(false); } void QtnPropertyQFontLineEditBttnHandler::updateEditor() { editor().setTextForProperty(stateProperty(), QtnPropertyDelegateQFont::fontToStrWithFormat(property())); editor().lineEdit->selectAll(); } void QtnPropertyQFontLineEditBttnHandler::onToolButtonClicked(bool) { auto property = &this->property(); volatile bool destroyed = false; auto connection = QObject::connect(property, &QObject::destroyed, [&destroyed]() mutable { destroyed = true; }); auto dialog = new QFontDialog(property->value(), editorBase()); auto dialogContainer = connectDialog(dialog); if (dialog->exec() == QDialog::Accepted && !destroyed) { auto font = property->value(); auto styleStrategy = font.styleStrategy(); int pixelSize = font.pixelSize(); font = dialog->currentFont(); if (pixelSize > 0) font.setPixelSize(font.pointSize()); font.setStyleStrategy(styleStrategy); property->setValue( font, delegate()->editReason() | QtnPropertyChangeReasonChildren); } if (!destroyed) QObject::disconnect(connection); Q_UNUSED(dialogContainer); } ================================================ FILE: QtnProperty/Delegates/GUI/PropertyDelegateQFont.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_QFONT_H #define PROPERTY_DELEGATE_QFONT_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/GUI/PropertyQFont.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateQFont : public QtnPropertyDelegateTypedEx { Q_DISABLE_COPY(QtnPropertyDelegateQFont) public: QtnPropertyDelegateQFont(QtnPropertyQFontBase &owner); static void Register(QtnPropertyDelegateFactory &factory); static QString fontToStrWithFormat( const QFont &font, const QString &format = QString("[%1]")); static QString fontToStr(const QFont &font); virtual bool propertyValueToStrImpl(QString &strValue) const override; protected: virtual void drawValueImpl( QStylePainter &painter, const QRect &rect) const override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; }; #endif // PROPERTY_DELEGATE_QFONT_H ================================================ FILE: QtnProperty/Delegates/GUI/PropertyDelegateQPen.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateQPen.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include "QtnProperty/Core/PropertyDouble.h" #include "QtnProperty/Core/PropertyQSize.h" #include "QtnProperty/Core/PropertyEnum.h" #include "QtnProperty/GUI/PropertyQColor.h" #include "QtnProperty/MultiProperty.h" #include #include #include QByteArray qtnShowNoPenAttr() { return QByteArrayLiteral("showNoPen"); } QByteArray qtnEditColorAttr() { return QByteArrayLiteral("editColor"); } QByteArray qtnEditStyleAttr() { return QByteArrayLiteral("editStyle"); } QByteArray qtnEditCapStyleAttr() { return QByteArrayLiteral("editCapStyle"); } QByteArray qtnEditJoinStyleAttr() { return QByteArrayLiteral("editJoinStyle"); } QByteArray qtnEditWidthAttr() { return QByteArrayLiteral("editWidth"); } void QtnPropertyDelegateQPenStyle::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyQPenStyleBase::staticMetaObject, &qtnCreateDelegate, qtnComboBoxDelegate()); } static void drawPenStyle(QPainter &painter, QRect rect, Qt::PenStyle penStyle) { rect.adjust(2, 2, -2, -2); QPen pen = painter.pen(); pen.setStyle(penStyle); painter.save(); painter.setPen(pen); auto midY = rect.center().y(); painter.drawLine(rect.left(), midY, rect.right(), midY); painter.restore(); } class QtnPropertyPenStyleItemDelegate : public QStyledItemDelegate { public: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; class QtnPropertyPenStyleComboBox : public QtnPropertyComboBox { public: explicit QtnPropertyPenStyleComboBox( QtnPropertyDelegate *delegate, QWidget *parent = Q_NULLPTR); protected: virtual void customPaint(QPainter &painter, const QRect &rect) override; }; class QtnPropertyPenStyleComboBoxHandler : public QtnPropertyEditorHandlerVT { public: QtnPropertyPenStyleComboBoxHandler( QtnPropertyDelegate *delegate, QComboBox &editor); private: void updateEditor() override; void onCurrentIndexChanged(int index); }; QtnPropertyDelegateQPenStyle::QtnPropertyDelegateQPenStyle( QtnPropertyQPenStyleBase &owner) : QtnPropertyDelegateTyped(owner) , m_showNoPen(false) { } void QtnPropertyDelegateQPenStyle::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnShowNoPenAttr(), m_showNoPen); } void QtnPropertyDelegateQPenStyle::drawValueImpl( QStylePainter &painter, const QRect &rect) const { if (stateProperty()->isMultiValue()) { QtnPropertyDelegateTyped::drawValueImpl(painter, rect); return; } Qt::PenStyle value = owner().value(); drawPenStyle(painter, rect, value); } QWidget *QtnPropertyDelegateQPenStyle::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { if (stateProperty()->isEditableByUser()) { QComboBox *combo = new QtnPropertyPenStyleComboBox(this, parent); combo->setLineEdit(nullptr); combo->setItemDelegate(new QtnPropertyPenStyleItemDelegate()); auto startStyle = m_showNoPen ? Qt::NoPen : Qt::SolidLine; for (auto ps = (int) startStyle; ps < Qt::CustomDashLine; ++ps) combo->addItem(QString(), QVariant::fromValue(Qt::PenStyle(ps))); combo->setGeometry(rect); new QtnPropertyPenStyleComboBoxHandler(this, *combo); if (inplaceInfo && stateProperty()->isEditableByUser()) combo->showPopup(); return combo; } return nullptr; } bool QtnPropertyDelegateQPenStyle::propertyValueToStrImpl( QString &strValue) const { auto info = QtnPropertyQPenBase::penStyleEnum().findByValue(int(owner().value())); if (!info) return false; strValue = info->displayName(); return true; } void QtnPropertyDelegateQPen::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyQPenBase::staticMetaObject, &qtnCreateDelegate, qtnLineEditDelegate()); } class QtnPropertyQPenLineEditHandler : public QtnPropertyEditorHandler { public: QtnPropertyQPenLineEditHandler( QtnPropertyDelegate *delegate, QLineEdit &editor); private: void updateEditor() override; }; QtnPropertyDelegateQPen::QtnPropertyDelegateQPen(QtnPropertyQPenBase &owner) : QtnPropertyDelegateTypedEx(owner) { } void QtnPropertyDelegateQPen::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { auto owner = &this->owner(); { bool editColor = true; info.loadAttribute(qtnEditColorAttr(), editColor); if (editColor) { addSubProperty( qtnCreateFieldProperty(owner, &QPen::color, &QPen::setColor, QtnPropertyQPen::colorKey(), QtnPropertyQPen::colorDisplayName(), QtnPropertyQPen::colorDescriptionFmt())); } } { bool editStyle = true; info.loadAttribute(qtnEditStyleAttr(), editStyle); if (editStyle) { addSubProperty( qtnCreateFieldProperty(owner, &QPen::style, &QPen::setStyle, QtnPropertyQPen::styleKey(), QtnPropertyQPen::styleDisplayName(), QtnPropertyQPen::styleDescriptionFmt())); } } { bool editWidth = true; info.loadAttribute(qtnEditWidthAttr(), editWidth); if (editWidth) { auto widthProperty = qtnCreateFieldProperty(owner, &QPen::widthF, &QPen::setWidthF, QtnPropertyQSize::widthKey(), QtnPropertyQSize::widthDisplayName(), QtnPropertyQSize::widthDescriptionFmt()); addSubProperty(widthProperty); widthProperty->setMinValue(0.0); } } { bool editCapStyle = true; info.loadAttribute(qtnEditCapStyleAttr(), editCapStyle); if (editCapStyle) { static_assert( sizeof(Qt::PenCapStyle) == sizeof(int), "enum size mismatch"); auto capStyleProperty = qtnCreateFieldProperty(owner, reinterpret_cast(&QPen::capStyle), reinterpret_cast(&QPen::setCapStyle), QtnPropertyQPen::capStyleKey(), QtnPropertyQPen::capStyleDisplayName(), QtnPropertyQPen::capStyleDescriptionFmt()); capStyleProperty->setEnumInfo(&QtnPropertyQPen::penCapStyleEnum()); addSubProperty(capStyleProperty); } } { bool editJoinStyle = true; info.loadAttribute(qtnEditJoinStyleAttr(), editJoinStyle); if (editJoinStyle) { static_assert( sizeof(Qt::PenJoinStyle) == sizeof(int), "enum size mismatch"); auto joinStyleProperty = qtnCreateFieldProperty(owner, reinterpret_cast(&QPen::joinStyle), reinterpret_cast(&QPen::setJoinStyle), QtnPropertyQPen::joinStyleKey(), QtnPropertyQPen::joinStyleDisplayName(), QtnPropertyQPen::joinStyleDescriptionFmt()); joinStyleProperty->setEnumInfo( &QtnPropertyQPen::penJoinStyleEnum()); addSubProperty(joinStyleProperty); } } } QWidget *QtnPropertyDelegateQPen::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *) { auto editor = new QLineEdit(parent); editor->setGeometry(rect); new QtnPropertyQPenLineEditHandler(this, *editor); return editor; } bool QtnPropertyDelegateQPen::propertyValueToStrImpl(QString &strValue) const { strValue = QtnPropertyQPen::rootDisplayValue(); return true; } void QtnPropertyPenStyleItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyledItemDelegate::paint(painter, option, index); auto penStyle = index.data(Qt::UserRole).value(); drawPenStyle(*painter, option.rect, penStyle); } QtnPropertyPenStyleComboBox::QtnPropertyPenStyleComboBox( QtnPropertyDelegate *delegate, QWidget *parent) : QtnPropertyComboBox(delegate, parent) { } void QtnPropertyPenStyleComboBox::customPaint( QPainter &painter, const QRect &rect) { auto penStyle = currentData().value(); drawPenStyle(painter, rect, penStyle); } QtnPropertyPenStyleComboBoxHandler::QtnPropertyPenStyleComboBoxHandler( QtnPropertyDelegate *delegate, QComboBox &editor) : QtnPropertyEditorHandlerVT(delegate, editor) { updateEditor(); QObject::connect(&editor, static_cast(&QComboBox::currentIndexChanged), this, &QtnPropertyPenStyleComboBoxHandler::onCurrentIndexChanged); } void QtnPropertyPenStyleComboBoxHandler::updateEditor() { updating++; if (stateProperty()->isMultiValue()) editor().setCurrentIndex(-1); else { int index = editor().findData(QVariant::fromValue(property().value())); editor().setCurrentIndex(index); } updating--; } void QtnPropertyPenStyleComboBoxHandler::onCurrentIndexChanged(int index) { if (index >= 0) { QVariant data = editor().itemData(index); if (data.canConvert()) onValueChanged(data.value()); } } QtnPropertyQPenLineEditHandler::QtnPropertyQPenLineEditHandler( QtnPropertyDelegate *delegate, QLineEdit &editor) : QtnPropertyEditorHandlerType(delegate, editor) { editor.setReadOnly(true); editor.setPlaceholderText(stateProperty()->isMultiValue() ? QtnMultiProperty::getMultiValuePlaceholder() : QtnPropertyQPen::rootDisplayValue()); } void QtnPropertyQPenLineEditHandler::updateEditor() { // do nothing } ================================================ FILE: QtnProperty/Delegates/GUI/PropertyDelegateQPen.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_QPEN_H #define PROPERTY_DELEGATE_QPEN_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/GUI/PropertyQPen.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateQPenStyle : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateQPenStyle) public: QtnPropertyDelegateQPenStyle(QtnPropertyQPenStyleBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: void applyAttributesImpl(const QtnPropertyDelegateInfo &info) override; void drawValueImpl( QStylePainter &painter, const QRect &rect) const override; QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; bool propertyValueToStrImpl(QString &strValue) const override; private: bool m_showNoPen; }; class QTN_IMPORT_EXPORT QtnPropertyDelegateQPen : public QtnPropertyDelegateTypedEx { Q_DISABLE_COPY(QtnPropertyDelegateQPen) public: QtnPropertyDelegateQPen(QtnPropertyQPenBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: void applyAttributesImpl(const QtnPropertyDelegateInfo &info) override; QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; bool propertyValueToStrImpl(QString &strValue) const override; }; #endif // PROPERTY_DELEGATE_QPEN_H ================================================ FILE: QtnProperty/Delegates/GUI/PropertyDelegateQVector3D.cpp ================================================ /******************************************************************************* Copyright (c) 2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateQVector3D.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Core/PropertyQPoint.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include "QtnProperty/Utils/DoubleSpinBox.h" #include #include QByteArray qtnZDisplayNameAttr() { return QByteArrayLiteral("zDisplayName"); } QByteArray qtnZDescriptionAttr() { return QByteArrayLiteral("zDescription"); } QtnPropertyDelegateQVector3D::QtnPropertyDelegateQVector3D( QtnPropertyQVector3DBase &owner) : QtnPropertyDelegateTypedEx(owner) , m_multiplier(1.0) , m_precision(std::numeric_limits::digits10 - 1) { addSubProperty(owner.createXProperty()); addSubProperty(owner.createYProperty()); addSubProperty(owner.createZProperty()); } void QtnPropertyDelegateQVector3D::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyQVector3DBase::staticMetaObject, &qtnCreateDelegate, QByteArrayLiteral("QVector3D")); } extern void qtnApplyQPointDelegateAttributes( QtnPropertyDelegate *to, const QtnPropertyDelegateInfo &info); void QtnPropertyDelegateQVector3D::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnSuffixAttr(), m_suffix); info.loadAttribute(qtnMultiplierAttr(), m_multiplier); info.loadAttribute(qtnPrecisionAttr(), m_precision); m_precision = qBound(0, m_precision, std::numeric_limits::digits10); if (!qIsFinite(m_multiplier) || qFuzzyCompare(m_multiplier, 0.0)) { m_multiplier = 1.0; } enum { X, Y, Z, TOTAL }; Q_ASSERT(subPropertyCount() == TOTAL); static const QtnSubPropertyInfo KEYS[TOTAL] = { { X, QtnPropertyQPoint::xKey(), qtnXDisplayNameAttr(), qtnXDescriptionAttr() }, { Y, QtnPropertyQPoint::yKey(), qtnYDisplayNameAttr(), qtnYDescriptionAttr() }, { Z, QtnPropertyQVector3D::zKey(), qtnZDisplayNameAttr(), qtnZDescriptionAttr() }, }; applySubPropertyInfos(info, KEYS, TOTAL); } QWidget *QtnPropertyDelegateQVector3D::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { return createValueEditorLineEdit(parent, rect, true, inplaceInfo); } bool QtnPropertyDelegateQVector3D::propertyValueToStrImpl( QString &strValue) const { auto value = owner().value(); QLocale locale; strValue = QtnPropertyQVector3D::getToStringFormat().arg( QtnDoubleSpinBox::valueToText( value.x() * m_multiplier, locale, m_precision, true) + m_suffix, QtnDoubleSpinBox::valueToText( value.y() * m_multiplier, locale, m_precision, true) + m_suffix, QtnDoubleSpinBox::valueToText( value.z() * m_multiplier, locale, m_precision, true) + m_suffix); return true; } ================================================ FILE: QtnProperty/Delegates/GUI/PropertyDelegateQVector3D.h ================================================ /******************************************************************************* Copyright (c) 2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/GUI/PropertyQVector3D.h" class QtnPropertyQVector3DBase; class QTN_IMPORT_EXPORT QtnPropertyDelegateQVector3D : public QtnPropertyDelegateTypedEx { Q_DISABLE_COPY(QtnPropertyDelegateQVector3D) QString m_suffix; double m_multiplier; int m_precision; public: QtnPropertyDelegateQVector3D(QtnPropertyQVector3DBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; ================================================ FILE: QtnProperty/Delegates/PropertyDelegate.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegate.h" #include "Utils/QtnConnections.h" #include "Utils/PropertyEditorHandler.h" #include "PropertyView.h" #include QtnPropertyDelegate::QtnPropertyDelegate(QtnPropertyBase &ownerProperty) : m_ownerProperty(&ownerProperty) , m_stateProperty(nullptr) { } QtnPropertyDelegate::~QtnPropertyDelegate() { if (m_editorHandler) m_editorHandler->cleanup(); } void QtnPropertyDelegate::init() { // do nothing } QtnPropertyChangeReason QtnPropertyDelegate::editReason() const { QtnPropertyChangeReason result = QtnPropertyChangeReasonEdit; if (stateProperty()->isMultiValue()) result |= QtnPropertyChangeReasonMultiEdit; return result; } void QtnPropertyDelegate::applySubPropertyInfo( const QtnPropertyDelegateInfo &info, const QtnSubPropertyInfo &subInfo) { QtnPropertyDelegateInfo subDelegateInfo; auto &subAttributes = subDelegateInfo.attributes; subAttributes = info.attributes; auto vSubDelegate = subAttributes.value(subInfo.key.toUtf8()); switch (vSubDelegate.type()) { case QVariant::Map: case QVariant::Hash: { auto vmap = vSubDelegate.toMap(); static const auto sNameKey = QStringLiteral("name"); for (auto it = vmap.cbegin(); it != vmap.cend(); ++it) { if (it.key() == sNameKey) { auto vname = vmap.value(sNameKey); subDelegateInfo.name = vname.type() == QVariant::ByteArray ? vname.toByteArray() : vname.toString().toUtf8(); } else { subAttributes[it.key().toUtf8()] = it.value(); } } } default: break; } auto p = subProperty(subInfo.id); p->setName(subInfo.key); info.storeAttributeValue(subInfo.displayNameAttr, p, &QtnPropertyBase::displayName, &QtnPropertyBase::setDisplayName); info.storeAttributeValue(subInfo.descriptionAttr, p, &QtnPropertyBase::description, &QtnPropertyBase::setDescription); p->setDelegateInfo(subDelegateInfo); } void QtnPropertyDelegate::applySubPropertyInfos( const QtnPropertyDelegateInfo &info, const QtnSubPropertyInfo *subInfos, int count) { for (int i = 0; i < count; i++) { applySubPropertyInfo(info, subInfos[i]); } } bool QtnPropertyDelegate::isSplittable() const { return false; } int QtnPropertyDelegate::subPropertyCountImpl() const { return 0; } QtnPropertyBase *QtnPropertyDelegate::subPropertyImpl(int index) { Q_UNUSED(index); return nullptr; } void QtnPropertyDelegate::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { Q_UNUSED(info); } QStyle::State QtnPropertyDelegate::state( bool isActive, const QtnSubItem &subItem) const { auto subState = subItem.state(); QStyle::State state = QStyle::State_Active; if (stateProperty()->isEditableByUser()) state |= QStyle::State_Enabled; if (isActive) { state |= QStyle::State_Selected; state |= QStyle::State_HasFocus; } if (subState == QtnSubItemStateUnderCursor) state |= QStyle::State_MouseOver; else if (subState == QtnSubItemStatePushed) state |= QStyle::State_Sunken; return state; } void QtnPropertyDelegate::addSubItemLock( QtnDrawContext &context, QList &subItems) { if (!stateProperty()->isUnlockable()) { return; } QtnSubItem item(context.rect.marginsRemoved(context.margins)); item.rect.setWidth(item.rect.height()); context.margins.setLeft(context.margins.left() + item.rect.height() + context.widget->valueLeftMargin()); item.setTextAsTooltip(stateProperty()->isLocked() ? QtnPropertyView::tr("Unlock") : QtnPropertyView::tr("Lock")); item.trackState(); if (item.rect.isValid()) { item.drawHandler = [this](QtnDrawContext &context, const QtnSubItem &item) { drawButton(context, item, QIcon(), stateProperty()->isLocked() ? QString::fromUtf8("\xF0\x9F\x93\x95") : QString::fromUtf8("\xF0\x9F\x93\x96")); }; item.eventHandler = [this](QtnEventContext &context, const QtnSubItem &, QtnPropertyToEdit *) -> bool { if ((context.eventType() == QEvent::MouseButtonPress) || (context.eventType() == QEvent::MouseButtonDblClick)) { QtnConnections connections; context.widget->connectPropertyToEdit( stateProperty(), connections); stateProperty()->toggleLock(editReason()); return true; } return false; }; subItems.append(item); } } QColor QtnPropertyDelegate::disabledTextColor(const QStylePainter &painter) { auto palette = painter.style()->standardPalette(); #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) return palette.color(QPalette::Active, QPalette::PlaceholderText); #else return palette.color(QPalette::Disabled, QPalette::Text); #endif } void QtnPropertyDelegate::addSubItemBranchNode( QtnDrawContext &context, QList &subItems) { if (!context.hasChildren) return; QtnSubItem brItem(context.rect.marginsRemoved(context.margins)); brItem.rect.setWidth(brItem.rect.height()); context.margins.setLeft(context.margins.left() + brItem.rect.height()); brItem.trackState(); if (!brItem.rect.isValid()) return; brItem.drawHandler = [this]( QtnDrawContext &context, const QtnSubItem &item) { auto &painter = *context.painter; QRectF branchRect = item.rect; qreal side = branchRect.height() / qreal(3.5); QColor fillClr = context.palette().color(QPalette::Text); QColor outlineClr = (item.state() != QtnSubItemStateNone) ? Qt::blue : context.palette().color(QPalette::Text); painter.save(); painter.setPen(outlineClr); QPainterPath branchPath; if (stateProperty()->isCollapsed()) { branchPath.moveTo( branchRect.left() + side, branchRect.top() + side); branchPath.lineTo(branchRect.right() - side - 1, branchRect.top() + branchRect.height() / qreal(2.0)); branchPath.lineTo( branchRect.left() + side, branchRect.bottom() - side); branchPath.closeSubpath(); } else { branchPath.moveTo( branchRect.left() + side, branchRect.top() + side); branchPath.lineTo( branchRect.right() - side, branchRect.top() + side); branchPath.lineTo( branchRect.left() + branchRect.width() / qreal(2.0), branchRect.bottom() - side - 1); branchPath.closeSubpath(); } if (painter.testRenderHint(QPainter::Antialiasing)) { painter.fillPath(branchPath, fillClr); painter.drawPath(branchPath); } else { painter.setRenderHint(QPainter::Antialiasing, true); painter.fillPath(branchPath, fillClr); painter.drawPath(branchPath); painter.setRenderHint(QPainter::Antialiasing, false); } painter.restore(); }; brItem.eventHandler = [this](QtnEventContext &context, const QtnSubItem &, QtnPropertyToEdit *) -> bool { if ((context.eventType() == QEvent::MouseButtonPress) || (context.eventType() == QEvent::MouseButtonDblClick)) { stateProperty()->toggleState(QtnPropertyStateCollapsed); return true; } return false; }; brItem.tooltipHandler = [this](QtnEventContext &, const QtnSubItem &) -> QString { return (stateProperty()->isCollapsed()) ? QtnPropertyView::tr("Click to expand") : QtnPropertyView::tr("Click to collapse"); }; subItems.append(brItem); } ================================================ FILE: QtnProperty/Delegates/PropertyDelegate.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_PROPERTY_DELEGATE_H #define QTN_PROPERTY_DELEGATE_H #include "QtnProperty/Config.h" #include "QtnProperty/Property.h" #include "PropertyDelegateAux.h" #include class QtnPropertyDelegateFactory; struct QtnSubPropertyInfo; class QtnPropertyEditorHandlerBase; class QTN_IMPORT_EXPORT QtnPropertyDelegate { Q_DISABLE_COPY(QtnPropertyDelegate) friend class QtnPropertyEditorHandlerBase; QtnPropertyDelegateFactory *m_factory = nullptr; QtnPropertyEditorHandlerBase *m_editorHandler = nullptr; public: virtual ~QtnPropertyDelegate(); virtual void init(); static QIcon resetIcon(); QtnPropertyChangeReason editReason() const; inline QtnPropertyBase *stateProperty() const; inline void setStateProperty(QtnPropertyBase *p); inline QtnPropertyBase *property(); inline const QtnPropertyBase *propertyImmutable() const; inline QtnPropertyDelegateFactory *factory() const; inline void setFactory(QtnPropertyDelegateFactory *factory); // for complex properties like PropertyQFont inline int subPropertyCount() const; inline QtnPropertyBase *subProperty(int index); // tune up with attributes inline void applyAttributes(const QtnPropertyDelegateInfo &info); // create GUI sub elements to present property on PropertyView inline void createSubItems( QtnDrawContext &context, QList &subItems); void addSubItemBranchNode( QtnDrawContext &context, QList &subItems); void applySubPropertyInfo( const QtnPropertyDelegateInfo &info, const QtnSubPropertyInfo &subInfo); void applySubPropertyInfos(const QtnPropertyDelegateInfo &info, const QtnSubPropertyInfo *subInfo, int count); virtual bool isSplittable() const; protected: QtnPropertyDelegate(QtnPropertyBase &ownerProperty); void drawButton(const QtnDrawContext &context, const QtnSubItem &item, const QIcon &icon, const QString &text); virtual int subPropertyCountImpl() const; virtual QtnPropertyBase *subPropertyImpl(int index); virtual void applyAttributesImpl(const QtnPropertyDelegateInfo &info); virtual void createSubItemsImpl( QtnDrawContext &context, QList &subItems) = 0; // helper functions QStyle::State state(bool isActive, const QtnSubItem &subItem) const; void addSubItemLock(QtnDrawContext &context, QList &subItems); static QColor disabledTextColor(const QStylePainter &painter); protected: QtnPropertyBase *m_ownerProperty; QtnPropertyBase *m_stateProperty; }; QtnPropertyBase *QtnPropertyDelegate::stateProperty() const { return m_stateProperty ? m_stateProperty : m_ownerProperty; } void QtnPropertyDelegate::setStateProperty(QtnPropertyBase *p) { m_stateProperty = p; } QtnPropertyBase *QtnPropertyDelegate::property() { return m_ownerProperty; } const QtnPropertyBase *QtnPropertyDelegate::propertyImmutable() const { return m_ownerProperty; } QtnPropertyDelegateFactory *QtnPropertyDelegate::factory() const { return m_factory; } void QtnPropertyDelegate::setFactory(QtnPropertyDelegateFactory *factory) { m_factory = factory; } int QtnPropertyDelegate::subPropertyCount() const { return subPropertyCountImpl(); } QtnPropertyBase *QtnPropertyDelegate::subProperty(int index) { return subPropertyImpl(index); } void QtnPropertyDelegate::applyAttributes(const QtnPropertyDelegateInfo &info) { applyAttributesImpl(info); } void QtnPropertyDelegate::createSubItems( QtnDrawContext &context, QList &subItems) { createSubItemsImpl(context, subItems); } #endif // QTN_PROPERTY_DELEGATE_H ================================================ FILE: QtnProperty/Delegates/PropertyDelegateAux.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateAux.h" #include "QtnProperty/PropertyView.h" #include "QtnProperty/MultiProperty.h" #include "QtnProperty/Utils/InplaceEditing.h" #include "QtnProperty/Utils/QtnConnections.h" #include #include QtnSubItem::QtnSubItem(const QRect &rect) : rect(rect) , m_trackState(false) , m_activeCount(0) , m_state(QtnSubItemStateNone) { } void QtnSubItem::setTextAsTooltip(const QString &text) { tooltipHandler = [text](QtnEventContext &, const QtnSubItem &) -> QString { return text; }; } void QtnSubItem::setPropertyNameAsTooltip(const QtnPropertyBase &property) { tooltipHandler = [&property]( QtnEventContext &, const QtnSubItem &) -> QString { return property.displayName(); }; } void QtnSubItem::setPropertyDescriptionAsTooltip( const QtnPropertyBase &property) { tooltipHandler = [&property]( QtnEventContext &, const QtnSubItem &) -> QString { auto descr = property.description(); if (descr.isEmpty()) return property.displayName(); return descr; }; } bool QtnSubItem::activate(QtnPropertyView *widget, QPoint mousePos) { if (!m_trackState) return false; Q_ASSERT(m_activeCount <= 1); if (m_activeCount > 1) return false; ++m_activeCount; if (m_state != QtnSubItemStateUnderCursor) { m_state = QtnSubItemStateUnderCursor; widget->viewport()->update(); selfEvent(QtnSubItemEvent::Activated, widget, mousePos); } return true; } bool QtnSubItem::deactivate(QtnPropertyView *widget, QPoint mousePos) { if (!m_trackState) return false; Q_ASSERT(m_activeCount > 0); if (m_activeCount == 0) return false; --m_activeCount; if ((m_activeCount == 0) && (m_state != QtnSubItemStateNone)) { m_state = QtnSubItemStateNone; widget->viewport()->update(); selfEvent(QtnSubItemEvent::Deactivated, widget, mousePos); } return true; } bool QtnSubItem::grabMouse(QtnPropertyView *widget, QPoint mousePos) { Q_ASSERT(m_activeCount > 0); Q_ASSERT(m_state == QtnSubItemStateUnderCursor); m_state = QtnSubItemStatePushed; widget->viewport()->update(); selfEvent(QtnSubItemEvent::PressMouse, widget, mousePos); return true; } bool QtnSubItem::releaseMouse(QtnPropertyView *widget, QPoint mousePos) { Q_ASSERT(m_activeCount > 0); Q_ASSERT(m_state == QtnSubItemStatePushed); m_state = QtnSubItemStateUnderCursor; widget->viewport()->update(); selfEvent(QtnSubItemEvent::ReleaseMouse, widget, mousePos); return true; } void QtnSubItem::draw(QtnDrawContext &context) const { if (drawHandler) drawHandler(context, *this); } bool QtnSubItem::event(QtnEventContext &context) { if (m_trackState) { switch (context.eventType()) { case QEvent::MouseButtonPress: case QEvent::MouseButtonDblClick: { auto event = context.eventAs(); if (event->button() == Qt::LeftButton) context.grabMouse(this, event->pos()); break; } case QEvent::MouseButtonRelease: { auto event = context.eventAs(); if ((event->button() == Qt::LeftButton) && (m_state == QtnSubItemStatePushed)) context.releaseMouse(this, event->pos()); break; } default: break; } } if (context.eventType() == QEvent::ToolTip) { if (!tooltipHandler) return false; QString tooltipText = tooltipHandler(context, *this); if (!tooltipText.isEmpty()) { auto event = context.eventAs(); QToolTip::showText( event->globalPos(), tooltipText, context.widget, rect); return true; } } if (eventHandler) { QtnPropertyToEdit propertyToEdit; bool result = eventHandler(context, *this, &propertyToEdit); if (propertyToEdit.isValid()) { auto editProperty = propertyToEdit.property(); bool editable = editProperty->isEditableByUser(); std::shared_ptr connections; if (editable) { connections = std::make_shared(); std::weak_ptr weakConnections = connections; connections->push_back( QObject::connect(editProperty, &QObject::destroyed, [weakConnections]() // { if (!weakConnections.expired()) weakConnections.lock()->clear(); })); context.widget->connectPropertyToEdit( editProperty, *connections.get()); } auto editor = propertyToEdit.createEditor(); if (editor) { if (editable) { QObject::connect(editor, &QObject::destroyed, [connections]() { connections->disconnect(); }); } qtnStartInplaceEdit(editor); } } return result; } return false; } bool QtnSubItem::selfEvent( QtnSubItemEvent::Type type, QtnPropertyView *widget, QPoint mousePos) { QtnSubItemEvent event_(type, mousePos); QtnEventContext context{ &event_, widget }; return event(context); } QStyle *QtnDrawContext::style() const { return widget->style(); } void QtnDrawContext::initStyleOption(QStyleOption &option) const { option.initFrom(widget); // State_MouseOver should be set explicitly option.state &= ~QStyle::State_MouseOver; } const QPalette &QtnDrawContext::palette() const { return widget->palette(); } QPalette::ColorGroup QtnDrawContext::colorGroup() const { return palette().currentColorGroup(); } QColor QtnDrawContext::alternateColor() const { auto color = palette().color(QPalette::Button); if (color == palette().color(QPalette::Window)) { color = color.darker(120); } return color; } QColor QtnDrawContext::textColorFor(bool normalText) const { QPalette::ColorRole role; QPalette::ColorGroup group = normalText ? palette().currentColorGroup() : QPalette::Disabled; if (isActive) { role = QPalette::HighlightedText; } else if (normalText) { role = QPalette::Text; } else { #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) group = QPalette::Active; role = QPalette::PlaceholderText; #else group = QPalette::Disabled; role = QPalette::Text; #endif } return palette().color(group, role); } void QtnEventContext::updateWidget() { widget->viewport()->update(); } bool QtnEventContext::grabMouse(QtnSubItem *subItem, QPoint mousePos) { return widget->grabMouseForSubItem(subItem, mousePos); } bool QtnEventContext::releaseMouse(QtnSubItem *subItem, QPoint mousePos) { return widget->releaseMouseForSubItem(subItem, mousePos); } QtnSubItemEvent::QtnSubItemEvent(Type type, QPoint mousePos) : QEvent((QEvent::Type) type) , m_mousePos(mousePos) { } QString qtnElidedText(const QPainter &painter, const QString &text, const QRect &rect, bool *elided) { QString newText = painter.fontMetrics().elidedText(text, Qt::ElideRight, rect.width()); if (elided) *elided = (newText != text); return newText; } void qtnDrawValueText( const QString &text, QPainter &painter, const QRect &rect, QStyle *style) { if (text.isEmpty()) return; auto textRect = rect; if (style) { textRect.adjust(style->pixelMetric(QStyle::PM_ButtonMargin), 0, 0, 0); } painter.drawText(textRect, Qt::AlignLeading | Qt::AlignVCenter, qtnElidedText(painter, text, textRect, nullptr)); } QtnPropertyToEdit::QtnPropertyToEdit() : m_property(nullptr) { } QtnPropertyToEdit::QtnPropertyToEdit(const QtnPropertyToEdit &other) { m_property = other.m_property; m_editorMaker = other.m_editorMaker; } void QtnPropertyToEdit::setup( QtnPropertyBase *property, const EditorMaker &editorMaker) { Q_ASSERT(property); Q_ASSERT(editorMaker); m_property = property; m_editorMaker = editorMaker; } QWidget *QtnPropertyToEdit::createEditor() const { if (!m_editorMaker) return nullptr; return m_editorMaker(); } bool QtnPropertyToEdit::isValid() const { return m_property && m_editorMaker; } ================================================ FILE: QtnProperty/Delegates/PropertyDelegateAux.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_PROPERTY_DELEGATE_AUX_H #define QTN_PROPERTY_DELEGATE_AUX_H #include "QtnProperty/FunctionalHelpers.h" #include #include #include #include class QtnPropertyBase; class QtnPropertyView; struct QtnDrawContext; struct QtnEventContext; class QTN_IMPORT_EXPORT QtnSubItemEvent : public QEvent { public: enum Type { Activated = 3 * QEvent::User + 15, Deactivated = 3 * QEvent::User + 16, PressMouse = 3 * QEvent::User + 17, ReleaseMouse = 3 * QEvent::User + 18 }; QtnSubItemEvent(Type type, QPoint mousePos); inline QPoint pos() const; inline int x() const; inline int y() const; private: QPoint m_mousePos; }; QPoint QtnSubItemEvent::pos() const { return m_mousePos; } int QtnSubItemEvent::x() const { return m_mousePos.x(); } int QtnSubItemEvent::y() const { return m_mousePos.y(); } enum QtnSubItemState { QtnSubItemStateNone, QtnSubItemStateUnderCursor, QtnSubItemStatePushed }; class QTN_IMPORT_EXPORT QtnPropertyToEdit { public: using EditorMaker = std::function; QtnPropertyToEdit(); QtnPropertyToEdit(const QtnPropertyToEdit &other); void setup(QtnPropertyBase *property, const EditorMaker &editorMaker); QtnPropertyBase *property() const; QWidget *createEditor() const; bool isValid() const; private: QtnPropertyBase *m_property; EditorMaker m_editorMaker; }; inline QtnPropertyBase *QtnPropertyToEdit::property() const { return m_property; } struct QTN_IMPORT_EXPORT QtnSubItem { using DrawHandler = std::function; using EventHandler = std::function; using ToolTipHandler = std::function; QtnSubItem(const QRect &rect); QRect rect; DrawHandler drawHandler; EventHandler eventHandler; ToolTipHandler tooltipHandler; inline QtnSubItemState state() const; inline void trackState(); void setTextAsTooltip(const QString &text); void setPropertyNameAsTooltip(const QtnPropertyBase &property); void setPropertyDescriptionAsTooltip(const QtnPropertyBase &property); private: bool activate(QtnPropertyView *widget, QPoint mousePos); bool deactivate(QtnPropertyView *widget, QPoint mousePos); bool grabMouse(QtnPropertyView *widget, QPoint mousePos); bool releaseMouse(QtnPropertyView *widget, QPoint mousePos); void draw(QtnDrawContext &context) const; bool event(QtnEventContext &context); bool selfEvent( QtnSubItemEvent::Type type, QtnPropertyView *widget, QPoint mousePos); bool m_trackState; quint8 m_activeCount; QtnSubItemState m_state; friend class QtnPropertyView; }; QtnSubItemState QtnSubItem::state() const { return m_state; } void QtnSubItem::trackState() { m_trackState = true; } struct QTN_IMPORT_EXPORT QtnDrawContext { public: QStylePainter *painter; const QtnPropertyView *widget; const QRect rect; QMargins margins; const int splitPos; const bool isActive; const bool hasChildren; QStyle *style() const; void initStyleOption(QStyleOption &option) const; const QPalette &palette() const; QPalette::ColorGroup colorGroup() const; QColor alternateColor() const; QColor textColorFor(bool normalText) const; }; struct QTN_IMPORT_EXPORT QtnEventContext { public: QEvent *event; QtnPropertyView *widget; inline int eventType() const; template EventT *eventAs() { return static_cast(event); } void updateWidget(); private: bool grabMouse(QtnSubItem *subItem, QPoint mousePos); bool releaseMouse(QtnSubItem *subItem, QPoint mousePos); friend struct QtnSubItem; }; int QtnEventContext::eventType() const { return static_cast(event->type()); } QTN_IMPORT_EXPORT QString qtnElidedText(const QPainter &painter, const QString &text, const QRect &rect, bool *elided = 0); QTN_IMPORT_EXPORT void qtnDrawValueText(const QString &text, QPainter &painter, const QRect &rect, QStyle *style = nullptr); template ::value>::type * = nullptr> void fixMinMaxVariant(QVariant &minv, QVariant &maxv) { bool minOk; bool maxOk; double min = minv.toDouble(&minOk); double max = maxv.toDouble(&maxOk); if (!minOk || max < min || !qIsFinite(min) || min < std::numeric_limits::lowest() || min > std::numeric_limits::max()) { minv = QVariant(); } else { minv = min; } if (!maxOk || max < min || !qIsFinite(max) || max < std::numeric_limits::lowest() || max > std::numeric_limits::max()) { maxv = QVariant(); } else { maxv = max; } } template ::value>::type * = nullptr> void fixMinMaxVariant(QVariant &minv, QVariant &maxv) { if (minv.type() == QVariant::ULongLong) { quint64 min = minv.toULongLong(); if (min > quint64(std::numeric_limits::max())) { minv = QVariant(); } else { minv = T(min); } } else { bool minOk; qint64 min = minv.toLongLong(&minOk); if (!minOk || min < qint64(std::numeric_limits::min()) || (min >= 0 && quint64(min) > quint64(std::numeric_limits::max()))) { minv = QVariant(); } else { minv = T(min); } } if (maxv.type() == QVariant::ULongLong) { quint64 max = maxv.toULongLong(); if (max > quint64(std::numeric_limits::max())) { maxv = QVariant(); } else { maxv = T(max); } } else { bool maxOk; qint64 max = maxv.toLongLong(&maxOk); if (!maxOk || max < qint64(std::numeric_limits::min()) || (max >= 0 && quint64(max) > quint64(std::numeric_limits::max()))) { maxv = QVariant(); } else { maxv = T(max); } } if (minv.isValid() && maxv.isValid() && maxv < minv) { minv = QVariant(); maxv = QVariant(); } } #endif // QTN_PROPERTY_DELEGATE_AUX_H ================================================ FILE: QtnProperty/Delegates/PropertyDelegateFactory.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateFactory.h" #include "Utils/PropertyDelegateMisc.h" #include "Utils/PropertyDelegatePropertySet.h" #include "Utils/PropertyDelegateGeoCoord.h" #include "Utils/PropertyDelegateGeoPoint.h" #include "Core/PropertyDelegateBool.h" #include "Core/PropertyDelegateInt.h" #include "Core/PropertyDelegateUInt.h" #include "Core/PropertyDelegateDouble.h" #include "Core/PropertyDelegateFloat.h" #include "Core/PropertyDelegateEnum.h" #include "Core/PropertyDelegateEnumFlags.h" #include "Core/PropertyDelegateQString.h" #include "Core/PropertyDelegateQPoint.h" #include "Core/PropertyDelegateQPointF.h" #include "Core/PropertyDelegateQSize.h" #include "Core/PropertyDelegateQSizeF.h" #include "Core/PropertyDelegateQRect.h" #include "Core/PropertyDelegateQRectF.h" #include "GUI/PropertyDelegateQColor.h" #include "GUI/PropertyDelegateQPen.h" #include "GUI/PropertyDelegateQBrush.h" #include "GUI/PropertyDelegateQFont.h" #include "GUI/PropertyDelegateQVector3D.h" #include "GUI/PropertyDelegateButton.h" #include "QtnProperty/PropertyQKeySequence.h" #include "QtnProperty/PropertyInt64.h" #include "QtnProperty/PropertyUInt64.h" #include "QtnProperty/MultiProperty.h" #include "QtnProperty/PropertyQVariant.h" #include QtnPropertyDelegateFactory::QtnPropertyDelegateFactory( QtnPropertyDelegateFactory *superFactory) : m_superFactory(nullptr) { setSuperFactory(superFactory); } void QtnPropertyDelegateFactory::setSuperFactory( QtnPropertyDelegateFactory *superFactory) { Q_ASSERT(m_superFactory != this); m_superFactory = superFactory; } QtnPropertyDelegate *QtnPropertyDelegateFactory::createDelegate( QtnPropertyBase &owner) { auto factory = this; while (factory) { auto result = factory->createDelegateInternal(owner); if (result) { result->setFactory(this); result->init(); return result; } factory = factory->m_superFactory; } auto delegateInfo = owner.delegateInfo(); QByteArray delegateName; if (delegateInfo) delegateName = delegateInfo->name; // create delegate stub if (delegateName.isEmpty()) { qWarning() << "Cannot find default delegate for property" << owner.name(); qWarning() << "Did you forget to register default delegate for " << owner.metaObject()->className() << "type?"; } else { qWarning() << "Cannot find delegate with name" << delegateName << "for property" << owner.name(); qWarning() << "Did you forget to register" << delegateName << "delegate for" << owner.metaObject()->className() << "type?"; } return qtnCreateDelegateError(owner, QString("Delegate <%1> unknown") .arg(QString::fromLatin1(delegateName))); } QtnPropertyDelegate *QtnPropertyDelegateFactory::createDelegateInternal( QtnPropertyBase &owner) { const QMetaObject *metaObject = owner.metaObject(); CreateFunction createFunction = nullptr; while (metaObject && !createFunction) { // try to find delegate factory by class name auto it = m_createItems.find(metaObject); if (it != m_createItems.end()) { // try to find delegate factory by name const CreateItem &createItem = it.value(); auto delegateInfo = owner.delegateInfo(); QByteArray delegateName; if (delegateInfo) delegateName = delegateInfo->name; if (delegateName.isEmpty()) { createFunction = createItem.defaultCreateFunction; } else { auto jt = createItem.createFunctions.find(delegateName); if (jt != createItem.createFunctions.end()) createFunction = jt.value(); } } metaObject = metaObject->superClass(); } if (!createFunction) return nullptr; return createFunction(owner); } bool QtnPropertyDelegateFactory::registerDelegateDefault( const QMetaObject *propertyMetaObject, const CreateFunction &createFunction, const QByteArray &delegateName) { Q_ASSERT(propertyMetaObject); Q_ASSERT(createFunction); // find or create creation record CreateItem &createItem = m_createItems[propertyMetaObject]; // register default create function createItem.defaultCreateFunction = createFunction; if (!delegateName.isEmpty()) { return registerDelegate( propertyMetaObject, createFunction, delegateName); } return true; } bool QtnPropertyDelegateFactory::registerDelegate( const QMetaObject *propertyMetaObject, const CreateFunction &createFunction, const QByteArray &delegateName) { Q_ASSERT(propertyMetaObject); Q_ASSERT(createFunction); Q_ASSERT(!delegateName.isEmpty()); // find or create creation record CreateItem &createItem = m_createItems[propertyMetaObject]; // register create function createItem.createFunctions[delegateName] = createFunction; return true; } bool QtnPropertyDelegateFactory::unregisterDelegate( const QMetaObject *propertyMetaObject) { Q_ASSERT(propertyMetaObject); auto it = m_createItems.find(propertyMetaObject); if (it == m_createItems.end()) return false; m_createItems.erase(it); return true; } bool QtnPropertyDelegateFactory::unregisterDelegate( const QMetaObject *propertyMetaObject, const QByteArray &delegateName) { Q_ASSERT(propertyMetaObject); Q_ASSERT(!delegateName.isEmpty()); auto it = m_createItems.find(propertyMetaObject); if (it == m_createItems.end()) return false; auto &createFunctions = it->createFunctions; auto it2 = createFunctions.find(delegateName); if (it2 == createFunctions.end()) return false; createFunctions.erase(it2); return true; } void QtnPropertyDelegateFactory::registerDefaultDelegates( QtnPropertyDelegateFactory &factory) { QtnPropertyDelegatePropertySet::Register(factory); QtnPropertyDelegateBoolCheck::Register(factory); QtnPropertyDelegateBoolCombobox::Register(factory); QtnPropertyDelegateInt::Register(factory); QtnPropertyDelegateUInt::Register(factory); QtnPropertyDelegateInt64::Register(factory); QtnPropertyDelegateUInt64::Register(factory); QtnPropertyDelegateDouble::Register(factory); QtnPropertyDelegateFloat::Register(factory); QtnPropertyDelegateEnum::Register(factory); QtnPropertyDelegateEnumFlags::Register(factory); QtnPropertyDelegateQString::Register(factory); QtnPropertyDelegateQStringFile::Register(factory); QtnPropertyDelegateQStringList::Register(factory); QtnPropertyDelegateQStringCallback::Register(factory); QtnPropertyDelegateQPoint::Register(factory); QtnPropertyDelegateQPointF::Register(factory); QtnPropertyDelegateQSize::Register(factory); QtnPropertyDelegateQSizeF::Register(factory); QtnPropertyDelegateQRect::Register(factory); QtnPropertyDelegateQRectF::Register(factory); QtnPropertyDelegateGeoCoord::Register(factory); QtnPropertyDelegateGeoPoint::Register(factory); QtnPropertyDelegateQColor::Register(factory); QtnPropertyDelegateQColorSolid::Register(factory); QtnPropertyDelegateQFont::Register(factory); QtnPropertyDelegateButton::Register(factory); QtnPropertyDelegateButtonLink::Register(factory); QtnPropertyDelegateQPenStyle::Register(factory); QtnPropertyDelegateQPen::Register(factory); QtnPropertyDelegateQBrushStyle::Register(factory); QtnPropertyDelegateQKeySequence::Register(factory); QtnPropertyDelegateQVector3D::Register(factory); QtnPropertyDelegateQVariant::Register(factory); QtnMultiPropertyDelegate::Register(factory); } static QScopedPointer _staticInstance; QtnPropertyDelegateFactory &QtnPropertyDelegateFactory::staticInstance() { if (!_staticInstance) { _staticInstance.reset(new QtnPropertyDelegateFactory); registerDefaultDelegates(*_staticInstance.data()); } return *_staticInstance.data(); } void QtnPropertyDelegateFactory::resetDefaultInstance( QtnPropertyDelegateFactory *factory) { if (_staticInstance) { auto currentFactory = factory; while (currentFactory) { if (currentFactory == _staticInstance.data()) { _staticInstance.take(); break; } currentFactory = currentFactory->superFactory(); } } _staticInstance.reset(factory); } ================================================ FILE: QtnProperty/Delegates/PropertyDelegateFactory.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_PROPERTY_DELEGATE_FACTORY_H #define QTN_PROPERTY_DELEGATE_FACTORY_H #include "PropertyDelegate.h" #include #include class QTN_IMPORT_EXPORT QtnPropertyDelegateFactory { Q_DISABLE_COPY(QtnPropertyDelegateFactory) public: using CreateFunction = std::function; explicit QtnPropertyDelegateFactory( QtnPropertyDelegateFactory *superFactory = nullptr); static void registerDefaultDelegates(QtnPropertyDelegateFactory &factory); inline QtnPropertyDelegateFactory *superFactory(); void setSuperFactory(QtnPropertyDelegateFactory *superFactory); QtnPropertyDelegate *createDelegate(QtnPropertyBase &owner); bool registerDelegateDefault(const QMetaObject *propertyMetaObject, const CreateFunction &createFunction, const QByteArray &delegateName = QByteArray()); bool registerDelegate(const QMetaObject *propertyMetaObject, const CreateFunction &createFunction, const QByteArray &delegateName); bool unregisterDelegate(const QMetaObject *propertyMetaObject); bool unregisterDelegate( const QMetaObject *propertyMetaObject, const QByteArray &delegateName); static QtnPropertyDelegateFactory &staticInstance(); static void resetDefaultInstance(QtnPropertyDelegateFactory *factory); private: QtnPropertyDelegate *createDelegateInternal(QtnPropertyBase &owner); QtnPropertyDelegateFactory *m_superFactory; struct CreateItem { CreateFunction defaultCreateFunction; QMap createFunctions; }; QMap m_createItems; }; QtnPropertyDelegateFactory *QtnPropertyDelegateFactory::superFactory() { return m_superFactory; } template QtnPropertyDelegate *qtnCreateDelegate(QtnPropertyBase &owner) { PropertyClass *theOwner = qobject_cast(&owner); if (!theOwner) return nullptr; return new PropertyDelegateClass(*theOwner); } #endif // QTN_PROPERTY_DELEGATE_FACTORY_H ================================================ FILE: QtnProperty/Delegates/Utils/PropertyDelegateGeoCoord.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateGeoCoord.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/Delegates/Utils/PropertyEditorHandler.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include QByteArray qtnGeoCoordDelegateName() { return QByteArrayLiteral("GeoCoord"); } void QtnPropertyDelegateGeoCoord::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegate(&QtnPropertyDoubleBase::staticMetaObject, &qtnCreateDelegate, qtnGeoCoordDelegateName()); } QString val2strGeoCoord(const double c) { QString s; s = c < 0 ? "-" : ""; double r = qAbs(c); int deg = static_cast(r); r -= deg; r *= 60; int min = static_cast(r); r -= min; r *= 60; int sec = static_cast(r); if (sec == 60) { sec = 0; ++min; if (min == 60) { min = 0; ++deg; } } QString txt = QString::fromUtf8("%1 %2° %3\' %4\"") .arg(s) .arg(deg, 3, 10, QChar('0')) .arg(min, 2, 10, QChar('0')) .arg(sec, 2, 10, QChar('0')); return txt; } double str2valGeoCoord(const QString &strVal) { static const QRegExp parserDeg( QString::fromUtf8(".*(\\d+)°.*"), Qt::CaseInsensitive); static const QRegExp parserMin(".*(\\d+)\'.*", Qt::CaseInsensitive); static const QRegExp parserSec(".*(\\d+\\.?\\d*)\".*", Qt::CaseInsensitive); static const QRegExp parserSign("^(-).*", Qt::CaseInsensitive); QString str = strVal; str.remove(" "); qreal val = 0.; if (parserDeg.exactMatch(str)) { if (parserDeg.capturedTexts().size() == 2) { val += parserDeg.capturedTexts().at(1).toInt(); } } if (parserMin.exactMatch(str)) { if (parserMin.capturedTexts().size() == 2) { val += parserMin.capturedTexts().at(1).toInt() / 60.; } } if (parserSec.exactMatch(str)) { if (parserSec.capturedTexts().size() == 2) { val += parserSec.capturedTexts().at(1).toDouble() / 60. / 60.; } } if (parserSign.exactMatch(str)) { val = -val; } return val; } class QtnPropertyGeoCoordLineEditHandler : public QtnPropertyEditorHandlerVT { public: QtnPropertyGeoCoordLineEditHandler( QtnPropertyDelegate *delegate, QLineEdit &editor); private: virtual void updateEditor() override; void onValueChanged(); }; QtnPropertyDelegateGeoCoord::QtnPropertyDelegateGeoCoord( QtnPropertyDoubleBase &owner) : QtnPropertyDelegateTyped(owner) { } QWidget *QtnPropertyDelegateGeoCoord::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { bool editable = stateProperty()->isEditableByUser(); auto lineEdit = createValueEditorLineEdit(parent, rect, !editable, inplaceInfo); new QtnPropertyGeoCoordLineEditHandler(this, *lineEdit); if (editable) qtnInitNumEdit(lineEdit, inplaceInfo, NUM_SIGNED_INT); return lineEdit; } bool QtnPropertyDelegateGeoCoord::propertyValueToStrImpl( QString &strValue) const { strValue = val2strGeoCoord(owner().value()); return true; } QtnPropertyGeoCoordLineEditHandler::QtnPropertyGeoCoordLineEditHandler( QtnPropertyDelegate *delegate, QLineEdit &editor) : QtnPropertyEditorHandlerVT(delegate, editor) { editor.setInputMask(QString::fromUtf8("# 000° 00\' 00\"")); updateEditor(); editor.installEventFilter(this); QObject::connect(&editor, &QLineEdit::editingFinished, this, &QtnPropertyGeoCoordLineEditHandler::onValueChanged); } void QtnPropertyGeoCoordLineEditHandler::updateEditor() { updating++; editor().setReadOnly(!stateProperty()->isEditableByUser()); if (stateProperty()->isMultiValue()) { editor().clear(); } else { editor().setText(val2strGeoCoord(property().value())); editor().selectAll(); } updating--; } void QtnPropertyGeoCoordLineEditHandler::onValueChanged() { if (canApply()) { property().setValue( str2valGeoCoord(editor().text()), delegate()->editReason()); } applyReset(); } ================================================ FILE: QtnProperty/Delegates/Utils/PropertyDelegateGeoCoord.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_GEOCOORD_H #define PROPERTY_DELEGATE_GEOCOORD_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyDouble.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateGeoCoord : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateGeoCoord) public: QtnPropertyDelegateGeoCoord(QtnPropertyDoubleBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; #endif // PROPERTY_DELEGATE_GEOCOORD_H ================================================ FILE: QtnProperty/Delegates/Utils/PropertyDelegateGeoPoint.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateGeoPoint.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include #include QByteArray qtnGeoPointDelegateName() { return QByteArrayLiteral("GeoPoint"); } void QtnPropertyDelegateGeoPoint::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegate(&QtnPropertyQPointFBase::staticMetaObject, &qtnCreateDelegate, qtnGeoPointDelegateName()); } QString QtnPropertyDelegateGeoPoint::longitudeKey() { return QStringLiteral("longitude"); } QString QtnPropertyDelegateGeoPoint::longitudeDisplayName() { return QCoreApplication::instance()->translate( "GeoPoint", QT_TRANSLATE_NOOP("GeoPoint", "Longitude")); } QString QtnPropertyDelegateGeoPoint::longitudeDescriptionFmt() { return QCoreApplication::instance()->translate( "GeoPoint", QT_TRANSLATE_NOOP("GeoPoint", "Longitude of %1")); } QString QtnPropertyDelegateGeoPoint::latitudeKey() { return QStringLiteral("latitude"); } QString QtnPropertyDelegateGeoPoint::latitudeDisplayName() { return QCoreApplication::instance()->translate( "GeoPoint", QT_TRANSLATE_NOOP("GeoPoint", "Latitude")); } QString QtnPropertyDelegateGeoPoint::latitudeDescriptionFmt() { return QCoreApplication::instance()->translate( "GeoPoint", QT_TRANSLATE_NOOP("GeoPoint", "Latitude of %1")); } QtnPropertyDelegateGeoPoint::QtnPropertyDelegateGeoPoint( QtnPropertyQPointFBase &owner) : QtnPropertyDelegateTypedEx(owner) { QtnPropertyDelegateInfo geoDelegate; geoDelegate.name = qtnGeoCoordDelegateName(); auto longitudeSubProperty = owner.createFieldProperty(&QPointF::x, &QPointF::setX, longitudeKey(), longitudeDisplayName(), longitudeDescriptionFmt()); longitudeSubProperty->setDelegateInfo(geoDelegate); auto latitudeSubProperty = owner.createFieldProperty(&QPointF::y, &QPointF::setY, latitudeKey(), latitudeDisplayName(), latitudeDescriptionFmt()); latitudeSubProperty->setDelegateInfo(geoDelegate); addSubProperty(longitudeSubProperty); addSubProperty(latitudeSubProperty); } void QtnPropertyDelegateGeoPoint::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { enum { X, Y, TOTAL }; Q_ASSERT(subPropertyCount() == TOTAL); static const QtnSubPropertyInfo KEYS[TOTAL] = { { X, longitudeKey(), qtnXDisplayNameAttr(), qtnXDescriptionAttr() }, { Y, latitudeKey(), qtnYDisplayNameAttr(), qtnYDescriptionAttr() }, }; applySubPropertyInfos(info, KEYS, TOTAL); } QWidget *QtnPropertyDelegateGeoPoint::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { return createValueEditorLineEdit(parent, rect, true, inplaceInfo); } extern QString val2strGeoCoord(const double); bool QtnPropertyDelegateGeoPoint::propertyValueToStrImpl( QString &strValue) const { QPointF value = owner().value(); strValue = QString("%1 x %2") .arg(val2strGeoCoord(value.x())) .arg(val2strGeoCoord(value.y())); return true; } ================================================ FILE: QtnProperty/Delegates/Utils/PropertyDelegateGeoPoint.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_DELEGATE_GEOPOINT_H #define PROPERTY_DELEGATE_GEOPOINT_H #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include "QtnProperty/Core/PropertyQPointF.h" class QTN_IMPORT_EXPORT QtnPropertyDelegateGeoPoint : public QtnPropertyDelegateTypedEx { Q_DISABLE_COPY(QtnPropertyDelegateGeoPoint) public: QtnPropertyDelegateGeoPoint(QtnPropertyQPointFBase &owner); static void Register(QtnPropertyDelegateFactory &factory); static QString longitudeKey(); static QString longitudeDisplayName(); static QString longitudeDescriptionFmt(); static QString latitudeKey(); static QString latitudeDisplayName(); static QString latitudeDescriptionFmt(); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; #endif // PROPERTY_DELEGATE_GEOPOINT_H ================================================ FILE: QtnProperty/Delegates/Utils/PropertyDelegateMisc.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateMisc.h" #include "QtnProperty/PropertyView.h" #include "QtnProperty/Utils/InplaceEditing.h" #include "QtnProperty/MultiProperty.h" #include #include static QIcon qtnResetIcon; QIcon QtnPropertyDelegate::resetIcon() { if (!qtnResetIcon.isNull()) return qtnResetIcon; const char iconData16[] = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/" "9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ" "bWFnZVJlYWR5ccllPAAAAsJJREFUeNp0UktIVGEUPve/" "j7l37h2aCSQRzEU46jg5D3QWBUnaWGKE" "WTmjNYobF4EERYWYD8bMVUW7XEVGtWsduIloZWoINRkR0oCLWaRCNa/76vzXuRdb+F/O/" "V/nfN85" "/3eY2tpaOGgwhAFCyKJpmNcNw/iz/" "y6bzVozMeHgj+d4kGU5JSvyZ5Zj22mAfWcPYq1tw8ESNiYI" "whtJlH673W7T4/EAWp2iKO94gX/IMIywLx440zTtdAVknJLc0rjL5SIIAhzHAc/ze8AsS/" "c383/z" "XcViMYFHGQcA6wRRFJ9KkjQiu2VAJisA2RwmCkj3oXCo7kr/" "ZY+TgfXjuA5MeUSRFeB4DsKRMCQH" "EuBv8EPfhUtAWKwUiZIDSUgOJt5jyIYDQFFrampmy2rZcmxqaoSpmcm3eDd96kT7suJRTN" "9hH9y6" "fQui0ch0WySWLpfLsLW1VQFAqVRdbaVlqKoKvX29q23RWHepVLLSDgQDMJOe2a2uPtIfaY" "kuaaoG" "9rvZGbDFQlHA+" "i0An893p1Qsga7roBENHj959AnveluaQ1l6tl8BS8a19VVAiQAbBTRNgwdz8znq" "SFkoIAafDDYez+" "qaLiHZKGY6inPCAQgFw3q9v16lwRRkc3Nz1moVBDB0A5rqAwV6jg11V3SJC6Ik" "LqD/mANA2c51n12jM33QQr5wEVVZAAYOVWoVUNIJZL6HPULlhrEbY/n/" "AOJd8ckz8U5Hb5R0FJtp" "F9c/" "BZdQQtb72Bss7Y2e8z3Q0Xk67TwiTbO5Ibi0ur6yWFVVNfTq5WvAIMDep2UcpVnRQGpXrw" "1C" "ajj1DP0/5HK5vQ72+rxAGALffmwIuJ/KfMmMLz5/" "QVY+rgDVm2bU2tYKQ8MpI9AcmEeftP9YQ3n7" "13YFwOvdW1SYvn7PxHA7gRZHk9AKaEtoc/igy7ZCOzs7Vtw/" "AQYASsoRySkHkqIAAAAASUVORK5C" "YII="; const char iconData32[] = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU" "1BAACx" "jwv8YQUAAAVlSURBVFhH1ZdrTJtVGMdP7y29F3qld4kwNgaGWwiYgYKySRZm0LmREca6aD" "IBRZcR" "xTDJzBLD0ImBbMmInxDj/GLcZJkf1EFU2KIfNGJiQBZmVkYYiUBbSluf5+W8tXcg4gd/" "y+Ht+zzn" "Pc//POc6shPYbLZ3tVqtjL5uCy59/" "ivUanUbCPgZhJRR05bZEQEqlUqoUCpsSqVyzJnlPJebmyuk" "rk3ZEQF8AZ+kpaUREMFVKpRvBoKBCbvdnk3dKdkRAaFQiHC5XCIWi4lCoSCQiXypTPqTw+" "HooFWS" "wqHPLWG1WnMhUAOPx6uBZyF8LRGLIKhSwQTncDiMmGAgSLw+" "L1ldWSXLq8s3fR7f8bm5uXu0mSi2" "JMBsNmcJBIJzIrHosEgoIgKhgIAIptdYwMe8RxIMBonf7yeeVQ/xeDx/" "raysvDQ7OztM3WE2FQBj" "eVgsEX8kgT8ggAnGBsYepwKzEQgEiM/rIyAAy/" "DMzEwjdTOknAM2p61TKpWOwLiKZXIZk2Y+n88E" "RzBAqoJgZkA7MRqN5O2es0bGGEHSLlgd1ga5VP6pTCYjQqEwHHTbgA67w05On3l9SavTHd" "Gn60ep" "hyGhABxzmMm/" "wEwWikSiqFTjENQdrCNFRYUkZ1cOYzv6QiOT5lgwC1VPVBHXi64fZSJZvUajuUtd" "YRIKKHis4Aak7ilMeWTPnY84SfsrbV6L1XyBGwxdS083fIf2fZX7YM4Fo9rCoWo5cZzU7n" "/6imfZ" "1woryENdUcQJcDqdVuj5H9I0KYfH/" "2dm796dS3re6ZnkCfjHtErtb9TMUF5RHoRHuC3oKel844zv" "0ZzsNq1Ke5maExI3sCaT6SSo53C4G2saC+50Hac7bunTDWWxwRG2HpY9eXvIexf75iB4+" "WbBkTgB" "PD73CLumsUFczzU11WuGDGM9zIUA44gB6+Fya3i+gZzt6f4qQ63Nh+" "B3qDslcQJWVlZtOOkwMLuZ" "2B2Oz+DAWaRV4oCJGnqru4sca2rsAaG1qerGEifA6/" "Xy8cmmFHuWt3fXFcaZhIv9798vKSmt06r1" "3cmylIxYATx2ybECMAvfj92+" "zRiTYDFZy3Tpumv0dVtECcCAMpk0nH62DA0NmWiVhCRa31slSgCm" "D9brOgZlM4BIJJLnmB/bwGAwaGFFrWeaM0NsMRgNc9QdJm4OWKyWPyMF4JDML8y/" "CtcuJa2yJWAn" "7YX9hAdP/" "E0UcgU58MwBNXWHiRPwZHX16Pr6ejj9HPgX8AdUKo1qgFbZFJ1OV+Nf9zfhNo5bN3Nc" "w6ZW8XjFD7RKmDgBRaVFfSWlJUxwZghgTuJGBEKOQlrPQ5WU9z24nNbK5fIRPMAwe2wmLR" "YL7Cc1" "vbRamDgBuNO5Tp74mgdnQOQwYINwrHbCuN6BIBW0ehiwGfR6/" "SWo8yX0VhO5meFSbnE13zUbzTcY" "YwRxZwHiXnJnXR25OjXw4UDUssSG/Gt+4lvzERim+3D1ugf+RWjFwOfx8/" "CmhEIx5ZHfHXq2nrS2" "t+2PPYqRhAKQhUX3y4ODl/o/Hh4JN4bg0KAQdo7geY/" "nBp6a2OvImxIGr6yqJF3dXR+YtKZ2xhhD" "UgHI/MP589e/uN7Z19uHPabWDbDxjR9QoJVIkQj6m5qbiMvV8kmGWtcI/" "oQ7ZEoBiPuhu3lmevry" "QP+gYHJiklpTk5OTTU61niL5BXt7cHum5oRsKgBZWFjIDfGCF6Z+" "nar99ptbZHx8nMxMz1DvBpmZ" "JlIMq6eiopwUlxRPQGJe02v0Y9SdlC0JYHmw9KCQhIKH4LOD8JqHV25Y78x/" "RmAofg9xyCiXE/w8" "Q2W4ufHFf4zb7ZYtLS1p6Ov/EUL+BmFpBSMtaelKAAAAAElFTkSuQmCC"; { auto bytes = QByteArray::fromBase64(iconData16); QPixmap pixmap; pixmap.loadFromData(bytes); qtnResetIcon.addPixmap(pixmap); } { auto bytes = QByteArray::fromBase64(iconData32); QPixmap pixmap; pixmap.loadFromData(bytes); qtnResetIcon.addPixmap(pixmap); } return qtnResetIcon; } void QtnPropertyDelegateWithValues::createSubItemsImpl( QtnDrawContext &context, QList &subItems) { addSubItemBackground(context, subItems); addSubItemSelection(context, subItems); addSubItemBranchNode(context, subItems); addSubItemLock(context, subItems); addSubItemName(context, subItems); addSubItemReset(context, subItems); addSubItemValues(context, subItems); } bool QtnPropertyDelegateWithValues::isSplittable() const { return true; } QtnPropertyDelegateWithValues::QtnPropertyDelegateWithValues( QtnPropertyBase &owner) : QtnPropertyDelegate(owner) { } void QtnPropertyDelegateWithValues::addSubItemBackground( QtnDrawContext &context, QList &subItems) { QtnSubItem bgItem(context.rect); if (!bgItem.rect.isValid()) return; bgItem.drawHandler = [](QtnDrawContext &context, const QtnSubItem &item) // { auto &painter = *context.painter; const auto &rect = item.rect; auto splitPos = context.splitPos; QPen oldPen = painter.pen(); QPen linesPen(context.palette().color(QPalette::Button)); painter.setPen(linesPen); // draw item borders painter.drawLine(rect.bottomLeft(), rect.bottomRight()); painter.drawLine(splitPos, rect.top(), splitPos, rect.bottom()); painter.setPen(oldPen); }; subItems.append(bgItem); } void QtnPropertyDelegateWithValues::addSubItemSelection( QtnDrawContext &context, QList &subItems) { QtnSubItem selItem(context.rect); if (!selItem.rect.isValid()) return; selItem.drawHandler = [](QtnDrawContext &context, const QtnSubItem &item) // { // highlight background if active property if (context.isActive) { context.painter->fillRect( item.rect, context.palette().color(QPalette::Highlight)); } }; subItems.append(selItem); } void QtnPropertyDelegateWithValues::addSubItemName( QtnDrawContext &context, QList &subItems) { QtnSubItem nameItem(context.rect.marginsRemoved(context.margins)); nameItem.rect.setRight(context.splitPos); nameItem.setPropertyDescriptionAsTooltip(*propertyImmutable()); if (!nameItem.rect.isValid()) return; nameItem.drawHandler = [this](QtnDrawContext &context, const QtnSubItem &item) { context.painter->save(); context.painter->setPen( context.textColorFor(stateProperty()->isEditableByUser())); if (!stateProperty()->valueIsDefault()) { auto font = context.painter->font(); font.setBold(true); context.painter->setFont(font); } context.painter->drawText(item.rect, int(Qt::AlignLeading | Qt::AlignVCenter) | Qt::TextSingleLine, qtnElidedText( *context.painter, property()->displayName(), item.rect)); context.painter->restore(); }; subItems.append(nameItem); } void QtnPropertyDelegateWithValues::addSubItemReset( QtnDrawContext &context, QList &subItems) { if (!stateProperty()->isResettable() || stateProperty()->valueIsDefault()) { return; } QtnSubItem resetItem(context.rect.marginsRemoved(context.margins)); resetItem.rect.setLeft(resetItem.rect.right() - resetItem.rect.height()); if (!resetItem.rect.isValid()) return; resetItem.setTextAsTooltip(QtnPropertyView::tr("Reset to default value")); resetItem.trackState(); resetItem.drawHandler = [this](QtnDrawContext &context, const QtnSubItem &item) { drawButton(context, item, resetIcon(), QtnPropertyView::tr("R", "Reset button text")); }; resetItem.eventHandler = [this](QtnEventContext &context, const QtnSubItem &, QtnPropertyToEdit *toEdit) -> bool { bool doClick = false; switch (context.eventType()) { case QtnSubItemEvent::ReleaseMouse: doClick = true; break; } if (doClick) { toEdit->setup(stateProperty(), [this]() -> QWidget * { stateProperty()->reset(editReason()); return nullptr; }); return true; } return false; }; subItems.append(resetItem); } void QtnPropertyDelegateWithValues::addSubItemValues( QtnDrawContext &context, QList &subItems) { auto rect = context.rect.marginsRemoved(context.margins); rect.setLeft(context.splitPos); if (stateProperty()->isResettable() && !stateProperty()->valueIsDefault()) { rect.setRight(rect.right() - rect.height()); } if (rect.isValid()) createSubItemValuesImpl(context, rect, subItems); } QtnPropertyDelegateWithValue::QtnPropertyDelegateWithValue( QtnPropertyBase &owner) : QtnPropertyDelegateWithValues(owner) { } void QtnPropertyDelegateWithValue::createSubItemValuesImpl( QtnDrawContext &context, const QRect &valueRect, QList &subItems) { QtnSubItem subItem(valueRect); if (createSubItemValueImpl(context, subItem)) subItems.append(subItem); } bool QtnPropertyDelegateWithValueEditor::propertyValueToStr( QString &strValue) const { return propertyValueToStrImpl(strValue); } QtnPropertyDelegateWithValueEditor::QtnPropertyDelegateWithValueEditor( QtnPropertyBase &owner) : QtnPropertyDelegateWithValue(owner) { } bool QtnPropertyDelegateWithValueEditor::propertyValueToStrImpl( QString &strValue) const { Q_UNUSED(strValue); return false; } bool QtnPropertyDelegateWithValueEditor::toolTipImpl(QString &strValue) const { return propertyValueToStrImpl(strValue); } bool QtnPropertyDelegateWithValueEditor::createSubItemValueImpl( QtnDrawContext &, QtnSubItem &subItemValue) { subItemValue.drawHandler = [this](QtnDrawContext &context, const QtnSubItem &item) { // draw property value auto oldBrush = context.painter->brush(); auto oldPen = context.painter->pen(); auto isNormalText = stateProperty()->isEditableByUser() && !stateProperty()->isMultiValue(); auto cg = isNormalText ? context.colorGroup() : QPalette::Disabled; auto color = context.textColorFor(isNormalText); auto bgColor = context.isActive ? context.palette().color(cg, QPalette::Highlight) : context.alternateColor(); context.painter->setBrush(bgColor); context.painter->setPen(color); drawValueImpl(*context.painter, item.rect); context.painter->setBrush(oldBrush); context.painter->setPen(oldPen); }; subItemValue.eventHandler = [this](QtnEventContext &context, const QtnSubItem &item, QtnPropertyToEdit *propertyToEdit) -> bool { bool doEdit = false; switch (context.eventType()) { case QEvent::MouseButtonDblClick: doEdit = (context.widget->propertyViewStyle() & QtnPropertyViewStyleDblClickActivation); break; case QEvent::MouseButtonRelease: doEdit = !(context.widget->propertyViewStyle() & QtnPropertyViewStyleDblClickActivation); break; case QEvent::KeyPress: doEdit = acceptKeyPressedForInplaceEditImpl( context.eventAs()); break; } if (doEdit) { auto ctx = &context; auto it = &item; propertyToEdit->setup(property(), [this, ctx, it]() -> QWidget * { QtnInplaceInfo inplaceInfo; inplaceInfo.activationEvent = ctx->event; return createValueEditorImpl( ctx->widget->viewport(), it->rect, &inplaceInfo); }); return true; } return false; }; subItemValue.tooltipHandler = [this](QtnEventContext &, const QtnSubItem &) -> QString { if (stateProperty()->isMultiValue()) { return QtnMultiProperty::getMultiValuePlaceholder(); } QString valueText; if (!toolTipImpl(valueText)) return QString(); return valueText; }; return true; } bool QtnPropertyDelegateWithValueEditor::isNormalPainterState( const QStylePainter &painter) const { if (!stateProperty()) { return false; } if (!stateProperty()->isEditableByUser()) { return false; } auto palette = painter.style()->standardPalette(); return palette.currentColorGroup() != QPalette::Disabled && painter.brush().color() != palette.color(QPalette::Highlight); } bool QtnPropertyDelegateWithValueEditor::isPlaceholderColor() const { return false; } void QtnPropertyDelegateWithValueEditor::drawValueImpl( QStylePainter &painter, const QRect &rect) const { if (stateProperty()->isMultiValue()) { qtnDrawValueText(QtnMultiProperty::getMultiValuePlaceholder(), painter, rect, painter.style()); return; } QString strValue; if (propertyValueToStrImpl(strValue)) { QPen oldPen; bool penChanged = false; if (isNormalPainterState(painter) && isPlaceholderColor()) { oldPen = painter.pen(); penChanged = true; painter.setPen(disabledTextColor(painter)); } qtnDrawValueText(strValue, painter, rect, painter.style()); if (penChanged) { painter.setPen(oldPen); } } } bool QtnPropertyDelegateWithValueEditor::acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const { int key = keyEvent->key(); return (key == Qt::Key_Space) || (key == Qt::Key_Return) || (key == Qt::Key_Enter); } QLineEdit *QtnPropertyDelegateWithValueEditor::createValueEditorLineEdit( QWidget *parent, const QRect &rect, bool readOnly, QtnInplaceInfo *inplaceInfo) const { QLineEdit *lineEdit = new QLineEdit(parent); lineEdit->setGeometry(rect); lineEdit->setReadOnly(readOnly); lineEdit->setPlaceholderText(QtnMultiProperty::getMultiValuePlaceholder()); if (!stateProperty()->isMultiValue()) { QString strValue; propertyValueToStrImpl(strValue); lineEdit->setText(strValue); } if (inplaceInfo) { lineEdit->selectAll(); } return lineEdit; } QtnPropertyDelegateError::QtnPropertyDelegateError( QtnPropertyBase &owner, const QString &error) : QtnPropertyDelegateWithValue(owner) , m_error(error) { } bool QtnPropertyDelegateError::createSubItemValueImpl( QtnDrawContext & /*context*/, QtnSubItem &subItemValue) { subItemValue.drawHandler = [this](QtnDrawContext &context, const QtnSubItem &item) { QPen oldPen = context.painter->pen(); context.painter->setPen(Qt::red); qtnDrawValueText(m_error, *context.painter, item.rect, context.style()); context.painter->setPen(oldPen); }; return true; } QtnPropertyDelegate *qtnCreateDelegateError( QtnPropertyBase &owner, QString error) { return new QtnPropertyDelegateError(owner, error); } QtnInplaceInfo::QtnInplaceInfo() : activationEvent(0) { } void QtnPropertyDelegate::drawButton(const QtnDrawContext &context, const QtnSubItem &item, const QIcon &icon, const QString &text) { auto style = context.style(); QStyleOptionToolButton option; context.initStyleOption(option); option.state = state(context.isActive, item); option.state &= ~QStyle::State_HasFocus; if (0 == (option.state & QStyle::State_Sunken)) { option.state |= QStyle::State_Raised; } // dont initialize styleObject from widget for QWindowsVistaStyle // this disables buggous animations if (style->inherits("QWindowsVistaStyle")) option.styleObject = nullptr; #ifdef Q_OS_MAC option.state &= ~QStyle::State_MouseOver; #endif option.features = QStyleOptionToolButton::None; option.subControls = QStyle::SC_ToolButton; option.activeSubControls = QStyle::SC_ToolButton; option.toolButtonStyle = Qt::ToolButtonIconOnly; option.rect = item.rect; option.arrowType = Qt::NoArrow; if (!icon.availableSizes().empty()) { option.icon = icon; option.iconSize = icon.actualSize(item.rect.size()); } else { option.text = text.isEmpty() ? QStringLiteral("*") : text; } // draw button style->drawComplexControl( QStyle::CC_ToolButton, &option, context.painter, context.widget); } ================================================ FILE: QtnProperty/Delegates/Utils/PropertyDelegateMisc.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_PROPERTY_DELEGATE_MISC_H #define QTN_PROPERTY_DELEGATE_MISC_H #include "QtnProperty/Delegates/PropertyDelegate.h" #include class QTN_IMPORT_EXPORT QtnInplaceInfo { public: QEvent *activationEvent; QtnInplaceInfo(); }; class QTN_IMPORT_EXPORT QtnPropertyDelegateWithValues : public QtnPropertyDelegate { Q_DISABLE_COPY(QtnPropertyDelegateWithValues) public: virtual bool isSplittable() const override; protected: QtnPropertyDelegateWithValues(QtnPropertyBase &owner); // override to define value part of property item virtual void createSubItemValuesImpl(QtnDrawContext &context, const QRect &valueRect, QList &subItems) = 0; virtual void createSubItemsImpl( QtnDrawContext &context, QList &subItems) override; // sub-items functions void addSubItemBackground( QtnDrawContext &context, QList &subItems); void addSubItemSelection( QtnDrawContext &context, QList &subItems); void addSubItemName(QtnDrawContext &context, QList &subItems); void addSubItemReset(QtnDrawContext &context, QList &subItems); void addSubItemValues(QtnDrawContext &context, QList &subItems); }; class QTN_IMPORT_EXPORT QtnPropertyDelegateWithValue : public QtnPropertyDelegateWithValues { Q_DISABLE_COPY(QtnPropertyDelegateWithValue) protected: QtnPropertyDelegateWithValue(QtnPropertyBase &owner); // override to define value part of property item virtual bool createSubItemValueImpl( QtnDrawContext &context, QtnSubItem &subItemValue) = 0; void createSubItemValuesImpl(QtnDrawContext &context, const QRect &valueRect, QList &subItems) override; }; class QTN_IMPORT_EXPORT QtnPropertyDelegateWithValueEditor : public QtnPropertyDelegateWithValue { Q_DISABLE_COPY(QtnPropertyDelegateWithValueEditor) public: inline QWidget *createValueEditor(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr); inline void drawValue(QStylePainter &painter, const QRect &rect) const; inline bool acceptKeyPressedForInplaceEdit(QKeyEvent *keyEvent) const; bool propertyValueToStr(QString &strValue) const; protected: QtnPropertyDelegateWithValueEditor(QtnPropertyBase &owner); // override if property value can be displayed as string virtual bool propertyValueToStrImpl(QString &strValue) const; // override if you need a custom tool tip virtual bool toolTipImpl(QString &strValue) const; bool createSubItemValueImpl( QtnDrawContext &context, QtnSubItem &subItemValue) override; bool isNormalPainterState(const QStylePainter &painter) const; virtual bool isPlaceholderColor() const; // override to draw property value or override propertyValueToStrImpl to draw value as text virtual void drawValueImpl(QStylePainter &painter, const QRect &rect) const; // override to filter key events that will activate property Editor virtual bool acceptKeyPressedForInplaceEditImpl(QKeyEvent *keyEvent) const; // override to implement property Editor virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) = 0; QLineEdit *createValueEditorLineEdit(QWidget *parent, const QRect &rect, bool readOnly, QtnInplaceInfo *inplaceInfo = nullptr) const; }; QWidget *QtnPropertyDelegateWithValueEditor::createValueEditor( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { return createValueEditorImpl(parent, rect, inplaceInfo); } void QtnPropertyDelegateWithValueEditor::drawValue( QStylePainter &painter, const QRect &rect) const { return drawValueImpl(painter, rect); } bool QtnPropertyDelegateWithValueEditor::acceptKeyPressedForInplaceEdit( QKeyEvent *keyEvent) const { return acceptKeyPressedForInplaceEditImpl(keyEvent); } template class QtnPropertyDelegateTyped : public DelegateClass { Q_DISABLE_COPY(QtnPropertyDelegateTyped) public: const PropertyClass &owner() const { return *static_cast(this->propertyImmutable()); } PropertyClass &owner() { return *static_cast(this->property()); } protected: QtnPropertyDelegateTyped(PropertyClass &owner) : DelegateClass(owner) { } }; template class QtnPropertyDelegateTypedEx : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateTypedEx) protected: QtnPropertyDelegateTypedEx(PropertyClass &owner) : QtnPropertyDelegateTyped(owner) { } virtual int subPropertyCountImpl() const override { return int(m_subProperties.size()); } virtual QtnPropertyBase *subPropertyImpl(int index) override { return m_subProperties[index].data(); } void addSubProperty(QtnPropertyBase *subProperty) { Q_ASSERT(subProperty); if (!subProperty) return; m_subProperties.emplace_back(subProperty); subProperty->connectMasterState(this->property()); } protected: std::deque> m_subProperties; }; class QTN_IMPORT_EXPORT QtnPropertyDelegateError : public QtnPropertyDelegateWithValue { Q_DISABLE_COPY(QtnPropertyDelegateError) public: QtnPropertyDelegateError(QtnPropertyBase &owner, const QString &error); protected: bool createSubItemValueImpl( QtnDrawContext &context, QtnSubItem &subItemValue) override; private: QString m_error; }; QTN_IMPORT_EXPORT QtnPropertyDelegate *qtnCreateDelegateError( QtnPropertyBase &owner, QString error); #endif // QTN_PROPERTY_DELEGATE_MISC_H ================================================ FILE: QtnProperty/Delegates/Utils/PropertyDelegatePropertySet.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegatePropertySet.h" #include "QtnProperty/Delegates/PropertyDelegateFactory.h" QtnPropertyDelegatePropertySet::QtnPropertyDelegatePropertySet( QtnPropertySet &owner) : QtnPropertyDelegate(owner) , m_owner(owner) { } void QtnPropertyDelegatePropertySet::Register( QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertySet::staticMetaObject, &qtnCreateDelegate, "Default"); } int QtnPropertyDelegatePropertySet::subPropertyCountImpl() const { return m_owner.childProperties().size(); } QtnPropertyBase *QtnPropertyDelegatePropertySet::subPropertyImpl(int index) { return m_owner.childProperties()[index]; } void QtnPropertyDelegatePropertySet::createSubItemsImpl( QtnDrawContext &context, QList &subItems) { // background { QtnSubItem bgItem(context.rect); if (bgItem.rect.isValid()) { bgItem.drawHandler = [](QtnDrawContext &context, const QtnSubItem &item) { // fill background context.painter->fillRect(item.rect, (context.isActive) ? context.palette().color(QPalette::Highlight) : context.alternateColor()); }; subItems.append(bgItem); } } addSubItemBranchNode(context, subItems); addSubItemLock(context, subItems); // property set name { QtnSubItem nameItem(context.rect.marginsRemoved(context.margins)); nameItem.setPropertyDescriptionAsTooltip(m_owner); if (nameItem.rect.isValid()) { nameItem.drawHandler = [this](QtnDrawContext &context, const QtnSubItem &item) { QFont oldFont = context.painter->font(); QPen oldPen = context.painter->pen(); // draw name QFont font = oldFont; font.setBold(true); context.painter->setFont(font); context.painter->setPen( context.textColorFor(stateProperty()->isEditableByUser())); QString elidedName = context.painter->fontMetrics().elidedText( property()->displayName(), Qt::ElideRight, item.rect.width()); context.painter->drawText(item.rect, Qt::AlignLeading | Qt::AlignVCenter | Qt::TextSingleLine, elidedName); context.painter->setPen(oldPen); context.painter->setFont(oldFont); }; subItems.append(nameItem); } } } ================================================ FILE: QtnProperty/Delegates/Utils/PropertyDelegatePropertySet.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_PROPERTY_DELEGATE_PROPERTY_SET_H #define QTN_PROPERTY_DELEGATE_PROPERTY_SET_H #include "QtnProperty/Delegates/PropertyDelegate.h" #include "QtnProperty/PropertySet.h" class QtnPropertySet; class QTN_IMPORT_EXPORT QtnPropertyDelegatePropertySet : public QtnPropertyDelegate { Q_DISABLE_COPY(QtnPropertyDelegatePropertySet) public: QtnPropertyDelegatePropertySet(QtnPropertySet &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: int subPropertyCountImpl() const override; QtnPropertyBase *subPropertyImpl(int index) override; void createSubItemsImpl( QtnDrawContext &context, QList &subItems) override; private: QtnPropertySet &m_owner; }; #endif // QTN_PROPERTY_DELEGATE_PROPERTY_SET_H ================================================ FILE: QtnProperty/Delegates/Utils/PropertyDelegateSliderBox.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateSliderBox.h" #include "QtnProperty/PropertyView.h" #include "QtnProperty/Auxiliary/PropertyMacro.h" #include "QtnProperty/PropertyDelegateAttrs.h" #include "QtnProperty/MultiProperty.h" #include #include QByteArray qtnFillColorAttr() { return QByteArrayLiteral("fillColor"); } QByteArray qtnLiveUpdateAttr() { return QByteArrayLiteral("liveUpdate"); } QByteArray qtnDrawBorderAttr() { return QByteArrayLiteral("drawBorder"); } QByteArray qtnUpdateByScrollAttr() { return QByteArrayLiteral("updateByScroll"); } QByteArray qtnAnimateAttr() { return QByteArrayLiteral("animate"); } QByteArray qtnToolTipAttr() { return QByteArrayLiteral("toolTip"); } QtnPropertyDelegateSlideBox::QtnPropertyDelegateSlideBox(QtnPropertyBase &owner) : QtnPropertyDelegateWithValue(owner) , m_liveUpdate(false) , m_drawBorder(true) , m_updateByScroll(true) , m_animate(false) , m_precision(std::numeric_limits::digits10 - 1) , m_multiplier(1.0) , m_boxFillColor(QColor::fromRgb(200, 200, 255)) , m_itemToolTip(QtnPropertyView::tr("Drag/Scroll mouse to change value")) , m_dragValuePart(0.0) , m_oldValuePart(0.0) , m_animateWidget(nullptr) { } QtnPropertyDelegateSlideBox::~QtnPropertyDelegateSlideBox() { m_animation.reset(); } void QtnPropertyDelegateSlideBox::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnFillColorAttr(), m_boxFillColor); info.loadAttribute(qtnLiveUpdateAttr(), m_liveUpdate); info.loadAttribute(qtnDrawBorderAttr(), m_drawBorder); info.loadAttribute(qtnUpdateByScrollAttr(), m_updateByScroll); info.loadAttribute(qtnAnimateAttr(), m_animate); info.loadAttribute(qtnToolTipAttr(), m_itemToolTip); info.loadAttribute(qtnSuffixAttr(), m_suffix); info.loadAttribute(qtnPrecisionAttr(), m_precision); info.loadAttribute(qtnMultiplierAttr(), m_multiplier); m_min = info.attributes.value(qtnMinAttr()); m_max = info.attributes.value(qtnMaxAttr()); m_precision = qBound(0, m_precision, std::numeric_limits::digits10); if (!qIsFinite(m_multiplier) || qFuzzyCompare(m_multiplier, 0.0)) { m_multiplier = 1.0; } } bool QtnPropertyDelegateSlideBox::createSubItemValueImpl( QtnDrawContext &context, QtnSubItem &subItemValue) { subItemValue.trackState(); subItemValue.setTextAsTooltip(m_itemToolTip); subItemValue.drawHandler = qtnMemFn(this, &QtnPropertyDelegateSlideBox::draw); subItemValue.eventHandler = qtnMemFn(this, &QtnPropertyDelegateSlideBox::event); if (m_animate) { m_dragValuePart = propertyValuePart(); m_animation.reset(new QVariantAnimation()); m_animateWidget = context.widget->viewport(); } return true; } void QtnPropertyDelegateSlideBox::draw( QtnDrawContext &context, const QtnSubItem &item) { if (stateProperty()->isMultiValue()) { qtnDrawValueText(QtnMultiProperty::getMultiValuePlaceholder(), *context.painter, item.rect, context.style()); return; } double valuePart = m_dragValuePart = (item.state() == QtnSubItemStatePushed || (m_animate && m_animation->state() == QVariantAnimation::Running)) ? dragValuePart() : propertyValuePart(); if (valuePart < 0.0) return; auto boxRect = item.rect; boxRect.adjust(2, 2, -2, -2); auto valueRect = boxRect; valueRect.setWidth(int(valuePart * valueRect.width())); auto &painter = *context.painter; painter.save(); auto palette = painter.style()->standardPalette(); auto colorGroup = stateProperty()->isEditableByUser() ? QPalette::Active : QPalette::Disabled; painter.fillRect(boxRect, palette.color(colorGroup, QPalette::Background)); painter.fillRect(valueRect, m_boxFillColor); painter.setPen(context.textColorFor(stateProperty()->isEditableByUser())); painter.drawRect(valueRect); if (m_drawBorder) painter.drawRect(boxRect); painter.restore(); qtnDrawValueText( valuePartToStr(valuePart), painter, boxRect, context.style()); } bool QtnPropertyDelegateSlideBox::event( QtnEventContext &context, const QtnSubItem &item, QtnPropertyToEdit *toEdit) { switch (context.eventType()) { case QEvent::KeyPress: { int key = context.eventAs()->key(); int increment = 0; if ((key == Qt::Key_Plus) || (key == Qt::Key_Equal)) increment = 1; else if ((key == Qt::Key_Minus) || (key == Qt::Key_Underscore)) increment = -1; else return false; toEdit->setup(property(), [this, increment]() -> QWidget * { incrementPropertyValueInternal(increment); return nullptr; }); return true; } case QEvent::Wheel: { if (m_updateByScroll) { int steps = context.eventAs()->angleDelta().y() / 120; toEdit->setup(property(), [this, steps]() -> QWidget * { incrementPropertyValueInternal(steps); return nullptr; }); return true; } return false; } case QtnSubItemEvent::Activated: { m_oldCursor = context.widget->cursor(); return true; } case QtnSubItemEvent::PressMouse: { if (!m_animate) { m_dragValuePart = toDragValuePart( context.eventAs()->x(), item.rect); context.updateWidget(); } return true; } case QEvent::MouseMove: { if (item.state() == QtnSubItemStatePushed) { auto dragValuePart = toDragValuePart( context.eventAs()->x(), item.rect); if (m_liveUpdate) { if (m_animate) m_animation->stop(); m_dragValuePart = dragValuePart; toEdit->setup( property(), [this, dragValuePart]() -> QWidget * { setPropertyValuePart(dragValuePart); return nullptr; }); } else if (!m_animate) { m_dragValuePart = dragValuePart; context.updateWidget(); } return true; } break; } case QtnSubItemEvent::ReleaseMouse: { context.widget->setCursor(m_oldCursor); auto dragValuePart = toDragValuePart( context.eventAs()->x(), item.rect); toEdit->setup(property(), [this, dragValuePart]() -> QWidget * { dragTo(dragValuePart); return nullptr; }); return true; } default: break; } return false; } void QtnPropertyDelegateSlideBox::incrementPropertyValueInternal(int steps) { if (m_animate) m_animation->stop(); incrementPropertyValue(steps); m_dragValuePart = propertyValuePart(); } double QtnPropertyDelegateSlideBox::toDragValuePart(int x, const QRect &rect) { double result = double(x - rect.left()) / rect.width(); if (result < 0.0) result = 0.0; else if (result > 1.0) result = 1.0; return result; } void QtnPropertyDelegateSlideBox::dragTo(double value) { if (m_animate) prepareAnimate(); setPropertyValuePart(value); if (m_animate) startAnimate(); else m_dragValuePart = value; } void QtnPropertyDelegateSlideBox::prepareAnimate() { if (m_animation->state() == QVariantAnimation::Running) { m_oldValuePart = m_dragValuePart; m_animation->stop(); } else { m_oldValuePart = m_dragValuePart = propertyValuePart(); } } void QtnPropertyDelegateSlideBox::startAnimate() { double startValue = m_oldValuePart; double endValue = propertyValuePart(); if (endValue == startValue) return; m_animation->setStartValue(startValue); m_animation->setEndValue(endValue); m_animation->setDuration(300); m_animation->setEasingCurve(QEasingCurve::OutCirc); QObject::connect(m_animation.data(), &QVariantAnimation::valueChanged, qtnMemFn(this, &QtnPropertyDelegateSlideBox::onAnimationChanged)); m_animation->start(); } void QtnPropertyDelegateSlideBox::onAnimationChanged(const QVariant &value) { m_dragValuePart = value.toDouble(); if (m_animateWidget) m_animateWidget->update(); } ================================================ FILE: QtnProperty/Delegates/Utils/PropertyDelegateSliderBox.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_PROPERTY_DELEGATE_SLIDER_BOX_H #define QTN_PROPERTY_DELEGATE_SLIDER_BOX_H #include "PropertyDelegateMisc.h" #include "Delegates/PropertyDelegateAux.h" #include "PropertyDelegateAttrs.h" #include "Utils/DoubleSpinBox.h" class QVariantAnimation; class QTN_IMPORT_EXPORT QtnPropertyDelegateSlideBox : public QtnPropertyDelegateWithValue { Q_DISABLE_COPY(QtnPropertyDelegateSlideBox) protected: QtnPropertyDelegateSlideBox(QtnPropertyBase &owner); virtual ~QtnPropertyDelegateSlideBox() override; void applyAttributesImpl(const QtnPropertyDelegateInfo &info) override; bool createSubItemValueImpl( QtnDrawContext &context, QtnSubItem &subItemValue) override; virtual void draw(QtnDrawContext &context, const QtnSubItem &item); virtual bool event(QtnEventContext &context, const QtnSubItem &item, QtnPropertyToEdit *toEdit); inline double dragValuePart() const; virtual double propertyValuePart() const = 0; virtual QString valuePartToStr(double valuePart) const = 0; virtual void incrementPropertyValue(int steps) = 0; virtual void setPropertyValuePart(double valuePart) = 0; void prepareAnimate(); void startAnimate(); bool m_liveUpdate; bool m_drawBorder; bool m_updateByScroll; bool m_animate; int m_precision; double m_multiplier; QColor m_boxFillColor; QString m_itemToolTip; QVariant m_min; QVariant m_max; QString m_suffix; private: void incrementPropertyValueInternal(int steps); double toDragValuePart(int x, const QRect &rect); void dragTo(double value); void onAnimationChanged(const QVariant &value); double m_dragValuePart; double m_oldValuePart; QWidget *m_animateWidget; QCursor m_oldCursor; QScopedPointer m_animation; }; double QtnPropertyDelegateSlideBox::dragValuePart() const { return m_dragValuePart; } template class QtnPropertyDelegateSlideBoxTyped : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateSlideBoxTyped) using ValueTypeStore = typename PropertyClass::ValueTypeStore; using ParentClass = QtnPropertyDelegateTyped; public: QtnPropertyDelegateSlideBoxTyped(PropertyClass &owner) : ParentClass(owner) { } protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override { ParentClass::applyAttributesImpl(info); fixMinMaxVariant(this->m_min, this->m_max); } ValueTypeStore minValue() const { const QVariant &mv = this->m_min; return mv.isValid() ? mv.value() : this->owner().minValue(); } ValueTypeStore maxValue() const { const QVariant &mv = this->m_max; return mv.isValid() ? mv.value() : this->owner().maxValue(); } ValueTypeStore currentValue() const { return qBound(minValue(), this->owner().value(), maxValue()); } template ::type * = nullptr> inline bool isHugeInterval() const { return false; } template ::value && sizeof(T) == 8>::type * = nullptr> inline bool isHugeInterval() const { using IntervalType = typename PropertyClass::IntervalType; const quint64 originalInterval = IntervalType(maxValue() - minValue()); const auto maxInterval = quint64(std::numeric_limits::max()); return originalInterval > maxInterval; } template ::value && sizeof(T) >= 8>::type * = nullptr> inline bool isHugeInterval() const { const auto originalInterval = maxValue() - minValue(); const auto maxInterval = double(std::numeric_limits::max()); return originalInterval > maxInterval; } template ::type * = nullptr> inline double interval(T to) const { using IntervalType = typename PropertyClass::IntervalType; return double(IntervalType(to - minValue())); } template ::value && sizeof(T) == 8>::type * = nullptr> inline double interval(T to) const { quint64 currentInterval = quint64(to - minValue()); if (isHugeInterval()) { if (to == maxValue()) { return 1.0; } using IntervalType = typename PropertyClass::IntervalType; const quint64 originalInterval = IntervalType(maxValue() - minValue()); auto halfCurrent = double(currentInterval / 2); auto halfOriginal = double(originalInterval / 2); return halfCurrent / halfOriginal; } return double(currentInterval); } template ::value && sizeof(T) >= 8>::type * = nullptr> inline double interval(T to) const { if (isHugeInterval()) { if (to == maxValue()) { return 1.0; } auto halfMin = minValue() * 0.5; auto halfMax = maxValue() * 0.5; auto halfTo = to * 0.5; const auto halfOriginal = halfMax - halfMin; auto halfCurrent = halfTo - halfMin; return halfCurrent / halfOriginal; } return double(to) - double(minValue()); } virtual double propertyValuePart() const override { return interval(currentValue()) / interval(maxValue()); } template ::value>::type * = nullptr> QString valueToStr(T value) const { if (this->m_multiplier == 1.0) { return QtnDoubleSpinBox::valueToText(value, QLocale(), qBound(0, this->m_precision, std::numeric_limits::digits10), true) + this->m_suffix; } return QtnDoubleSpinBox::valueToText(double(value) * this->m_multiplier, QLocale(), this->m_precision, true) + this->m_suffix; } template ::value>::type * = nullptr> QString valueToStr(T value) const { if (this->m_multiplier == 1.0) { return QLocale().toString(value) + this->m_suffix; } return QtnDoubleSpinBox::valueToText(double(value) * this->m_multiplier, QLocale(), this->m_precision, true) + this->m_suffix; } virtual QString valuePartToStr(double valuePart) const override { return valueToStr(partToValue(valuePart)); } virtual void incrementPropertyValue(int steps) override { this->owner().incrementValue(this->editReason(), steps); } virtual void setPropertyValuePart(double valuePart) override { this->owner().setValue( partToValue(valuePart), this->editReason()); } template ::value && sizeof(T) >= 8>::type * = nullptr> ValueTypeStore partToValue(double valuePart) const { Q_ASSERT(valuePart >= 0.0); Q_ASSERT(valuePart <= 1.0); if (isHugeInterval()) { if (valuePart == 1.0) { return maxValue(); } const auto originalInterval = maxValue() - minValue(); auto halfOriginal = originalInterval * 0.5; auto halfMin = minValue() * 0.5; auto value = ValueTypeStore(valuePart * halfOriginal); return (value + halfMin) * 2.0; } auto value = ValueTypeStore(valuePart * interval(maxValue())); return value + minValue(); } template ::value && sizeof(T) == 8>::type * = nullptr> ValueTypeStore partToValue(double valuePart) const { Q_ASSERT(valuePart >= 0.0); Q_ASSERT(valuePart <= 1.0); ValueTypeStore value; if (isHugeInterval()) { if (valuePart == 1.0) { return maxValue(); } using IntervalType = typename PropertyClass::IntervalType; const quint64 originalInterval = IntervalType(maxValue() - minValue()); auto dividedInterval = originalInterval / 2; value = ValueTypeStore(valuePart * dividedInterval) * 2; } else { value = ValueTypeStore(valuePart * interval(maxValue())); } return value + minValue(); } template ::type * = nullptr> ValueTypeStore partToValue(double valuePart) const { Q_ASSERT(valuePart >= 0.0); Q_ASSERT(valuePart <= 1.0); auto value = ValueTypeStore(valuePart * interval(maxValue())); return value + minValue(); } }; #endif // QTN_PROPERTY_DELEGATE_SLIDER_BOX_H ================================================ FILE: QtnProperty/Delegates/Utils/PropertyEditorAux.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2019 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyEditorAux.h" #include "QtnProperty/Delegates/PropertyDelegate.h" #include "PropertyDelegateMisc.h" #include "QtnProperty/MultiProperty.h" #include #include #include #include #include QtnLineEditBttn::QtnLineEditBttn( QWidget *parent, const QString &bttnText, QLineEdit *lineEdit) : QWidget(parent) { QHBoxLayout *layout = new QHBoxLayout(this); layout->setMargin(0); layout->setSpacing(0); if (!lineEdit) lineEdit = new QLineEdit(this); else lineEdit->setParent(this); this->lineEdit = lineEdit; layout->addWidget(lineEdit); toolButton = new QToolButton(this); toolButton->setText(bttnText); toolButton->setFocusPolicy(Qt::StrongFocus); layout->addWidget(toolButton); setFocusProxy(lineEdit); setAutoFillBackground(true); } QtnComboBoxBttn::QtnComboBoxBttn(QWidget *parent, const QString &bttnText) : QWidget(parent) { QHBoxLayout *layout = new QHBoxLayout(this); layout->setMargin(0); layout->setSpacing(0); comboBox = new QComboBox(this); layout->addWidget(comboBox); toolButton = new QToolButton(this); toolButton->setText(bttnText); toolButton->setFocusPolicy(Qt::StrongFocus); layout->addWidget(toolButton); setFocusProxy(comboBox); setAutoFillBackground(true); } void QtnLineEditBttn::setTextForProperty( QtnPropertyBase *property, const QString &text) { if (property->isMultiValue()) { lineEdit->clear(); lineEdit->setPlaceholderText( QtnMultiProperty::getMultiValuePlaceholder()); } else { lineEdit->setText(text); lineEdit->setPlaceholderText(QString()); } } bool qtnAcceptForLineEdit(QKeyEvent *keyEvent) { if (keyEvent->type() != QEvent::KeyPress) return false; // any printable key press is acceptable QString text = keyEvent->text(); return (text.size() == 1 && text[0].isPrint()); } void qtnInitLineEdit(QLineEdit *lineEdit, QtnInplaceInfo *inplaceInfo) { if (!lineEdit || !inplaceInfo) return; if (!lineEdit->isReadOnly() && (inplaceInfo->activationEvent->type() == QEvent::KeyPress)) { QKeyEvent *keyEvent = static_cast(inplaceInfo->activationEvent); if (qtnAcceptForLineEdit(keyEvent)) { lineEdit->setText(keyEvent->text()); auto completer = lineEdit->completer(); if (completer) completer->setCompletionPrefix(lineEdit->text()); return; } } else { lineEdit->selectAll(); } } bool qtnAcceptForNumEdit(QKeyEvent *keyEvent, QtnNumType type) { if (keyEvent->type() != QEvent::KeyPress) return false; // any numeric key press is acceptable QString text = keyEvent->text(); if (text.size() == 1) { QChar c = text.at(0); QLocale locale; switch (type) { case NUM_FLOAT: if (c == QLatin1Char('.') || c == locale.decimalPoint()) { return true; } // fall through case NUM_SIGNED_INT: if (c == QLatin1Char('-') || c == QLatin1Char('+') || c == locale.negativeSign() || c == locale.positiveSign()) { return true; } // fall through case NUM_UNSIGNED_INT: if (c.isDigit()) { return true; } break; } } return false; } void qtnInitNumEdit( QWidget *numEdit, QtnInplaceInfo *inplaceInfo, QtnNumType type) { if (nullptr != inplaceInfo && inplaceInfo->activationEvent->type() == QEvent::KeyPress) { auto keyEvent = static_cast(inplaceInfo->activationEvent); if (qtnAcceptForNumEdit(keyEvent, type)) { keyEvent = new QKeyEvent(keyEvent->type(), keyEvent->key(), keyEvent->modifiers(), keyEvent->text()); QCoreApplication::postEvent(numEdit, keyEvent); } } } QtnPropertyComboBox::QtnPropertyComboBox( QtnPropertyDelegate *delegate, QWidget *parent) : QComboBox(parent) , m_delegate(delegate) { } void QtnPropertyComboBox::paintEvent(QPaintEvent *event) { auto rect = event->rect(); QComboBox::paintEvent(event); QPainter painter(this); if (stateProperty()->isMultiValue()) { if (isEnabled()) { #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) auto color = palette().color(QPalette::Active, QPalette::PlaceholderText); #else auto color = palette().color(QPalette::Disabled, QPalette::Text); #endif painter.setPen(color); } qtnDrawValueText(QtnMultiProperty::getMultiValuePlaceholder(), painter, rect, style()); } else if (currentIndex() >= 0) { customPaint(painter, rect); } } void QtnPropertyComboBox::customPaint(QPainter &, const QRect &) { // do nothing } ================================================ FILE: QtnProperty/Delegates/Utils/PropertyEditorAux.h ================================================ /******************************************************************************* Copyright (c) 2012-2019 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_EDITOR_AUX_H #define PROPERTY_EDITOR_AUX_H #include "QtnProperty/Config.h" #include "QtnProperty/Delegates/PropertyDelegate.h" #include #include #include class QKeyEvent; class QtnInplaceInfo; class QTN_IMPORT_EXPORT QtnLineEditBttn : public QWidget { public: QtnLineEditBttn(QWidget *parent, const QString &bttnText = "...", QLineEdit *lineEdit = nullptr); void setTextForProperty(QtnPropertyBase *property, const QString &text); QLineEdit *lineEdit; QToolButton *toolButton; }; class QTN_IMPORT_EXPORT QtnPropertyComboBox : public QComboBox { QtnPropertyDelegate *m_delegate; public: explicit QtnPropertyComboBox( QtnPropertyDelegate *delegate, QWidget *parent = Q_NULLPTR); inline QtnPropertyDelegate *delegate() const; inline QtnPropertyBase *property() const; inline QtnPropertyBase *stateProperty() const; private: virtual void paintEvent(QPaintEvent *event) override; protected: virtual void customPaint(QPainter &painter, const QRect &rect); }; QtnPropertyDelegate *QtnPropertyComboBox::delegate() const { return m_delegate; } QtnPropertyBase *QtnPropertyComboBox::property() const { return m_delegate->property(); } QtnPropertyBase *QtnPropertyComboBox::stateProperty() const { return m_delegate->stateProperty(); } class QTN_IMPORT_EXPORT QtnComboBoxBttn : public QWidget { public: QtnComboBoxBttn(QWidget *parent, const QString &bttnText = "..."); QComboBox *comboBox; QToolButton *toolButton; }; enum QtnNumType { NUM_SIGNED_INT, NUM_UNSIGNED_INT, NUM_FLOAT }; QTN_IMPORT_EXPORT bool qtnAcceptForLineEdit(QKeyEvent *keyEvent); QTN_IMPORT_EXPORT bool qtnAcceptForNumEdit( QKeyEvent *keyEvent, QtnNumType type); QTN_IMPORT_EXPORT void qtnInitLineEdit( QLineEdit *lineEdit, QtnInplaceInfo *inplaceInfo); QTN_IMPORT_EXPORT void qtnInitNumEdit( QWidget *numEdit, QtnInplaceInfo *inplaceInfo, QtnNumType type); #endif // PROPERTY_EDITOR_AUX_H ================================================ FILE: QtnProperty/Delegates/Utils/PropertyEditorHandler.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyEditorHandler.h" #include "QtnProperty/Utils/InplaceEditing.h" #include "QtnProperty/Utils/QtnConnections.h" #include #include #include QtnPropertyEditorHandlerBase::QtnPropertyEditorHandlerBase( QtnPropertyDelegate *delegate, QWidget &editor) : QObject(&editor) , reverted(false) , returned(false) , m_delegate(delegate) , m_editor(&editor) { Q_ASSERT(delegate); //Q_ASSERT(!delegate->m_editorHandler); delegate->m_editorHandler = this; auto property = delegate->property(); Q_ASSERT(property); QObject::connect(property, &QtnPropertyBase::propertyDidChange, this, &QtnPropertyEditorHandlerBase::onPropertyDidChange, Qt::QueuedConnection); QObject::connect(property, &QObject::destroyed, this, &QtnPropertyEditorHandlerBase::onPropertyDestroyed); auto stateProperty = delegate->stateProperty(); if (stateProperty != property) { QObject::connect(stateProperty, &QtnPropertyBase::propertyDidChange, this, &QtnPropertyEditorHandlerBase::onPropertyDidChange, Qt::QueuedConnection); } } void QtnPropertyEditorHandlerBase::revertInput() { reverted = true; updateEditor(); } void QtnPropertyEditorHandlerBase::cleanup() { if (m_delegate) { m_delegate->m_editorHandler = nullptr; m_delegate = nullptr; } if (m_editor) m_editor->removeEventFilter(this); qtnStopInplaceEdit(); } QtnPropertyEditorHandlerBase::~QtnPropertyEditorHandlerBase() { cleanup(); } bool QtnPropertyEditorHandlerBase::eventFilter(QObject *obj, QEvent *event) { switch (event->type()) { case QEvent::KeyPress: { auto keyEvent = static_cast(event); // revert all changes switch (keyEvent->key()) { case Qt::Key_Escape: revertInput(); break; case Qt::Key_Enter: case Qt::Key_Return: returned = true; break; default: break; } } break; default: break; } return QObject::eventFilter(obj, event); } bool QtnPropertyEditorHandlerBase::canApply() const { if (nullptr != stateProperty() && stateProperty()->isEditableByUser()) return (!reverted && (returned || !stateProperty()->isMultiValue())); return false; } void QtnPropertyEditorHandlerBase::applyReset() { reverted = false; returned = false; } QtnPropertyEditorHandlerBase::DialogContainerPtr QtnPropertyEditorHandlerBase::connectDialog(QDialog *dialog) { DialogContainerPtr result(new DialogContainer(dialog)); connectDialog(result); return result; } void QtnPropertyEditorHandlerBase::connectDialog( const DialogContainerPtr &containerPtr) { Q_ASSERT(nullptr != containerPtr); auto dialog = containerPtr->dialog; Q_ASSERT(nullptr != dialog); auto parent = dialog->parent(); Q_ASSERT(nullptr != parent); QObject::connect(parent, &QObject::destroyed, [containerPtr]() { containerPtr->dialog->setParent(nullptr); }); } void QtnPropertyEditorHandlerBase::onPropertyDestroyed() { cleanup(); } void QtnPropertyEditorHandlerBase::onPropertyDidChange( QtnPropertyChangeReason reason) { if (!sender()) { return; } if (reason & (QtnPropertyChangeReasonValue | QtnPropertyChangeReasonState)) { if (propertyBase() == sender() || stateProperty() == sender()) updateEditor(); } } QtnPropertyEditorHandlerBase::DialogContainer::DialogContainer(QDialog *dialog) : dialog(dialog) { } QtnPropertyEditorHandlerBase::DialogContainer::~DialogContainer() { if (nullptr != dialog && nullptr == dialog->parent()) delete dialog; } ================================================ FILE: QtnProperty/Delegates/Utils/PropertyEditorHandler.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_EDITOR_HANDLER_H #define PROPERTY_EDITOR_HANDLER_H #include "QtnProperty/Config.h" #include "QtnProperty/Property.h" #include "QtnProperty/Delegates/PropertyDelegate.h" #include #include #include #include class QDialog; class QTN_IMPORT_EXPORT QtnPropertyEditorHandlerBase : public QObject { public: void cleanup(); virtual ~QtnPropertyEditorHandlerBase() override; protected: QtnPropertyEditorHandlerBase( QtnPropertyDelegate *delegate, QWidget &editor); inline QtnPropertyDelegate *delegate() const; inline QtnPropertyBase *propertyBase() const; inline QtnPropertyBase *stateProperty() const; inline QWidget *editorBase() const; virtual void updateEditor() = 0; virtual void revertInput(); virtual bool eventFilter(QObject *obj, QEvent *event) override; virtual bool canApply() const; virtual void applyReset(); struct DialogContainer { QDialog *dialog; DialogContainer(QDialog *dialog); ~DialogContainer(); }; typedef std::shared_ptr DialogContainerPtr; static DialogContainerPtr connectDialog(QDialog *dialog); static void connectDialog(const DialogContainerPtr &containerPtr); protected: bool reverted : 1; bool returned : 1; private: QtnPropertyDelegate *m_delegate; QWidget *m_editor; private: void onPropertyDestroyed(); void onPropertyDidChange(QtnPropertyChangeReason reason); }; QtnPropertyBase *QtnPropertyEditorHandlerBase::propertyBase() const { if (m_delegate) return m_delegate->property(); return nullptr; } QtnPropertyDelegate *QtnPropertyEditorHandlerBase::delegate() const { return m_delegate; } QtnPropertyBase *QtnPropertyEditorHandlerBase::stateProperty() const { if (m_delegate) return m_delegate->stateProperty(); return nullptr; } QWidget *QtnPropertyEditorHandlerBase::editorBase() const { return m_editor; } template class QtnPropertyEditorHandler : public QtnPropertyEditorHandlerBase { protected: typedef QtnPropertyEditorHandler QtnPropertyEditorHandlerType; QtnPropertyEditorHandler( QtnPropertyDelegate *delegate, PropertyEditorClass &editor) : QtnPropertyEditorHandlerBase(delegate, editor) { } PropertyClass &property() const { return *static_cast(propertyBase()); } PropertyEditorClass &editor() const { return *static_cast(editorBase()); } }; template class QtnPropertyEditorHandlerVT : public QtnPropertyEditorHandler { protected: using Inherited = QtnPropertyEditorHandler; using ValueType = typename PropertyClass::ValueType; using ValueTypeStore = typename PropertyClass::ValueTypeStore; QtnPropertyEditorHandlerVT( QtnPropertyDelegate *delegate, PropertyEditorClass &editor) : Inherited(delegate, editor) , updating(0) { newValue = this->property().value(); } void onValueChanged(ValueType value) { if (updating > 0) return; newValue = value; updateValue(); } virtual void updateValue() { if (this->propertyBase()) this->property().setValue(newValue, this->delegate()->editReason()); } ValueTypeStore newValue; unsigned updating; }; template class QtnPropertyEditorBttnHandler : public QtnPropertyEditorHandler { private: typedef QtnPropertyEditorHandler Inherited; protected: typedef QtnPropertyEditorBttnHandler QtnPropertyEditorHandlerType; QtnPropertyEditorBttnHandler( QtnPropertyDelegate *delegate, PropertyEditorClass &editor) : Inherited(delegate, editor) , double_clicked(false) { } virtual void onToolButtonClick() = 0; virtual bool eventFilter(QObject *obj, QEvent *event) override { if (nullptr != this->stateProperty() && this->stateProperty()->isEditableByUser()) switch (event->type()) { case QEvent::MouseButtonDblClick: double_clicked = true; return true; case QEvent::MouseButtonRelease: if (double_clicked) { double_clicked = false; onToolButtonClick(); return true; } break; default: break; } return Inherited::eventFilter(obj, event); } private: bool double_clicked; }; #endif // PROPERTY_EDITOR_HANDLER_H ================================================ FILE: QtnProperty/Enum.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "Enum.h" #include #include #include QtnEnumInfo::QtnEnumInfo() : m_case_sensitivity(Qt::CaseInsensitive) { } QtnEnumInfo::QtnEnumInfo(const QString &name) : m_case_sensitivity(Qt::CaseInsensitive) , m_name(name) { } QtnEnumInfo::QtnEnumInfo( const QString &name, QVector &staticValues) : m_case_sensitivity(Qt::CaseInsensitive) , m_name(name) { m_values.swap(staticValues); } QtnEnumInfo::QtnEnumInfo( const QString &name, const QVector &staticValues) : m_case_sensitivity(Qt::CaseSensitive) , m_name(name) , m_values(staticValues) { } QtnEnumInfo QtnEnumInfo::withMetaEnum(const QMetaEnum &metaEnum, bool translate) { QtnEnumInfo enumInfo(QLatin1String(metaEnum.scope()) + QStringLiteral("::") + QLatin1String(metaEnum.name())); auto &vec = enumInfo.getVector(); int count = metaEnum.keyCount(); vec.reserve(count); for (int i = 0; i < count; i++) { const char *key = metaEnum.key(i); QString keyStr = QLatin1String(key); vec.append(QtnEnumValueInfo(metaEnum.value(i), keyStr, translate ? QCoreApplication::translate( metaEnum.scope(), key, metaEnum.name()) : keyStr)); } return enumInfo; } const QtnEnumValueInfo *QtnEnumInfo::findByValue(QtnEnumValueType value) const { const QtnEnumValueInfo *result = nullptr; forEachEnumValue( [&result, value](const QtnEnumValueInfo &enumValue) -> bool { if (enumValue.value() == value) { result = &enumValue; return false; } return true; }); return result; } const QtnEnumValueInfo *QtnEnumInfo::findByName(const QString &name) const { const QtnEnumValueInfo *result = nullptr; forEachEnumValue([&result, &name, this]( const QtnEnumValueInfo &enumValue) -> bool { if (QString::compare(enumValue.name(), name, m_case_sensitivity) == 0) { result = &enumValue; return false; } return true; }); return result; } const QtnEnumValueInfo *QtnEnumInfo::findByDisplayName( const QString &displayName, Qt::CaseSensitivity cs) const { const QtnEnumValueInfo *result = nullptr; forEachEnumValue( [&result, &displayName, cs](const QtnEnumValueInfo &enumValue) -> bool { if (QString::compare(enumValue.displayName(), displayName, cs) == 0) { result = &enumValue; return false; } return true; }); return result; } const QtnEnumValueInfo *QtnEnumInfo::fromStr(const QString &str) const { return findByName(str.trimmed()); } bool QtnEnumInfo::toStr(QString &str, const QtnEnumValueInfo *value) const { if (!value) return false; str = value->name(); return true; } QtnEnumValueInfo::QtnEnumValueInfo() : m_value(0) , m_state(QtnEnumValueStateInvalid) { } QtnEnumValueInfo::QtnEnumValueInfo( QtnEnumValueType value, const QString &name, QtnEnumValueState state) : QtnEnumValueInfo(value, name, name, state) { } QtnEnumValueInfo::QtnEnumValueInfo(QtnEnumValueType value, const QString &name, const QString &displayName, QtnEnumValueState state) : m_value(value) , m_name(name) , m_displayName(displayName) , m_state(state) { if (displayName.isEmpty()) m_displayName = name; } bool QtnEnumInfo::toStr(QString &str, QtnEnumValueType value) const { return toStr(str, findByValue(value)); } ================================================ FILE: QtnProperty/Enum.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_ENUM_H #define QTN_ENUM_H #include "Config.h" #include #include #include typedef qint32 QtnEnumValueType; enum QtnEnumValueStateFlag { QtnEnumValueStateNone = 0x0000, QtnEnumValueStateHidden = 0x0001, QtnEnumValueStateObsolete = 0x0002, QtnEnumValueStateInvalid = 0x0004 }; Q_DECLARE_FLAGS(QtnEnumValueState, QtnEnumValueStateFlag) Q_DECLARE_OPERATORS_FOR_FLAGS(QtnEnumValueState) class QTN_IMPORT_EXPORT QtnEnumValueInfo { public: QtnEnumValueInfo(); QtnEnumValueInfo(QtnEnumValueType value, const QString &name, QtnEnumValueState state = QtnEnumValueStateNone); QtnEnumValueInfo(QtnEnumValueType value, const QString &name, const QString &displayName, QtnEnumValueState state = QtnEnumValueStateNone); inline QtnEnumValueType value() const; inline void setValue(QtnEnumValueType value); inline const QString &name() const; inline const QString &displayName() const; inline QtnEnumValueState state() const; private: QtnEnumValueType m_value; QString m_name; QString m_displayName; QtnEnumValueState m_state; }; QtnEnumValueType QtnEnumValueInfo::value() const { return m_value; } void QtnEnumValueInfo::setValue(QtnEnumValueType value) { m_value = value; } const QString &QtnEnumValueInfo::name() const { return m_name; } const QString &QtnEnumValueInfo::displayName() const { return m_displayName; } QtnEnumValueState QtnEnumValueInfo::state() const { return m_state; } class QTN_IMPORT_EXPORT QtnEnumInfo { public: QtnEnumInfo(); QtnEnumInfo(const QString &name); QtnEnumInfo(const QString &name, QVector &staticValues); QtnEnumInfo( const QString &name, const QVector &staticValues); inline bool isValid() const; inline const QString &name() const; static QtnEnumInfo withMetaEnum( const QMetaEnum &metaEnum, bool translate = false); template static inline QtnEnumInfo withEnum(bool translate = false) { return withMetaEnum(QMetaEnum::fromType(), translate); } template bool forEachEnumValue(Pred pred) const { for (const auto &value : m_values) { if (!pred(value)) return false; } return true; } const QtnEnumValueInfo *findByValue(QtnEnumValueType value) const; const QtnEnumValueInfo *findByName(const QString &name) const; const QtnEnumValueInfo *findByDisplayName(const QString &displayName, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; const QtnEnumValueInfo *fromStr(const QString &str) const; bool toStr(QString &str, const QtnEnumValueInfo *value) const; bool toStr(QString &str, QtnEnumValueType value) const; Qt::CaseSensitivity getCaseSensitivity() const; void setCaseSensitivity(Qt::CaseSensitivity value); inline QVector &getVector(); inline const QVector &getVector() const; private: Qt::CaseSensitivity m_case_sensitivity; QString m_name; QVector m_values; }; bool QtnEnumInfo::isValid() const { return !m_name.isEmpty() && !m_values.isEmpty(); } const QString &QtnEnumInfo::name() const { return m_name; } QVector &QtnEnumInfo::getVector() { return m_values; } const QVector &QtnEnumInfo::getVector() const { return m_values; } #endif // QTN_ENUM_H ================================================ FILE: QtnProperty/FunctionalHelpers.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "Config.h" #include template std::function qtnMemFn(T *t, R (T::*memFn)(Types...) const) { return [t, memFn](Types... args) { return std::mem_fn(memFn)(t, std::forward(args)...); }; } template std::function qtnMemFn(T *t, R (T::*memFn)(Types...)) { return [t, memFn](Types... args) { return std::mem_fn(memFn)(t, std::forward(args)...); }; } ================================================ FILE: QtnProperty/GUI/PropertyButton.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyButton.h" QtnPropertyButton::QtnPropertyButton(QObject *parent) : QtnProperty(parent) { switchState(QtnPropertyStateNonSerialized, true); } void QtnPropertyButton::invokeClick() { emit click(this); } void QtnPropertyButton::setClickHandler( const std::function &clickHandler) { QObject::connect(this, &QtnPropertyButton::click, clickHandler); } void QtnPropertyButton::invokePreDrawButton(QStyleOptionButton *option) { Q_ASSERT(option); emit preDrawButton(this, option); } bool QtnPropertyButton::fromStrImpl(const QString &, QtnPropertyChangeReason) { return false; } bool QtnPropertyButton::toStrImpl(QString &) const { return false; } ================================================ FILE: QtnProperty/GUI/PropertyButton.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_BUTTON_H #define PROPERTY_BUTTON_H #include "QtnProperty/Property.h" #include class QStyleOptionButton; class QTN_IMPORT_EXPORT QtnPropertyButton : public QtnProperty { Q_OBJECT public: explicit QtnPropertyButton(QObject *parent); void invokeClick(); void setClickHandler( const std::function &clickHandler); inline QtnPropertyButton &operator=(const QtnPropertyButton &); Q_SIGNALS: void click(const QtnPropertyButton *property); public: void invokePreDrawButton(QStyleOptionButton *option); Q_SIGNALS: void preDrawButton( const QtnPropertyButton *property, QStyleOptionButton *option); protected: bool fromStrImpl(const QString &, QtnPropertyChangeReason) override; bool toStrImpl(QString &str) const override; }; QtnPropertyButton &QtnPropertyButton::operator=(const QtnPropertyButton &) { // do nothing return *this; } #endif // PROPERTY_BUTTON_H ================================================ FILE: QtnProperty/GUI/PropertyQBrush.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQBrush.h" #include QtnPropertyQBrushStyle::StrBrushStyleMap QtnPropertyQBrushStyle::CreateStr2BrushStyle() { StrBrushStyleMap str2BrushStyle = { // { QByteArray(QT_TR_NOOP("NoBrush")), Qt::NoBrush }, { QByteArray(QT_TR_NOOP("Solid")), Qt::SolidPattern }, { QByteArray(QT_TR_NOOP("Dense1Pattern")), Qt::Dense1Pattern }, { QByteArray(QT_TR_NOOP("Dense2Pattern")), Qt::Dense2Pattern }, { QByteArray(QT_TR_NOOP("Dense3Pattern")), Qt::Dense3Pattern }, { QByteArray(QT_TR_NOOP("Dense4Pattern")), Qt::Dense4Pattern }, { QByteArray(QT_TR_NOOP("Dense5Pattern")), Qt::Dense5Pattern }, { QByteArray(QT_TR_NOOP("Dense6Pattern")), Qt::Dense6Pattern }, { QByteArray(QT_TR_NOOP("Dense7Pattern")), Qt::Dense7Pattern }, { QByteArray(QT_TR_NOOP("HorPattern")), Qt::HorPattern }, { QByteArray(QT_TR_NOOP("VerPattern")), Qt::VerPattern }, { QByteArray(QT_TR_NOOP("CrossPattern")), Qt::CrossPattern }, { QByteArray(QT_TR_NOOP("BDiagPattern")), Qt::BDiagPattern }, { QByteArray(QT_TR_NOOP("FDiagPattern")), Qt::FDiagPattern }, { QByteArray(QT_TR_NOOP("DiagCrossPattern")), Qt::DiagCrossPattern }, { QByteArray(QT_TR_NOOP("LinearGradientPattern")), Qt::LinearGradientPattern }, { QByteArray(QT_TR_NOOP("RadialGradientPattern")), Qt::RadialGradientPattern }, { QByteArray(QT_TR_NOOP("ConicalGradientPattern")), Qt::ConicalGradientPattern }, { QByteArray(QT_TR_NOOP("TexturePattern")), Qt::TexturePattern } }; return str2BrushStyle; } QtnPropertyQBrushStyle::BrushStyleToStrMap QtnPropertyQBrushStyle::CreateBrushStyle2Str() { BrushStyleToStrMap brushStyle2Str; auto map = CreateStr2BrushStyle(); for (auto it = map.constBegin(); it != map.constEnd(); ++it) brushStyle2Str[it.value()] = it.key(); return brushStyle2Str; } bool QtnPropertyQBrushStyleBase::brushStyleToStr( Qt::BrushStyle brushStyle, QByteArray &result) { static auto brushStyle2Str = QtnPropertyQBrushStyle::CreateBrushStyle2Str(); auto it = brushStyle2Str.find(brushStyle); if (it != brushStyle2Str.end()) { result = it.value(); return true; } return false; } QtnPropertyQBrushStyle::QtnPropertyQBrushStyle(QObject *parent) : QtnSinglePropertyValue(parent) { } bool QtnPropertyQBrushStyle::translateBrushStyle( Qt::BrushStyle brushStyle, QString &result) { QByteArray id; if (!QtnPropertyQBrushStyleBase::brushStyleToStr(brushStyle, id)) return false; result = tr(id.data()); return true; } QtnPropertyQBrushStyleBase::QtnPropertyQBrushStyleBase(QObject *parent) : QtnSinglePropertyBase(parent) { } bool QtnPropertyQBrushStyleBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { static auto str2BrushStyle = QtnPropertyQBrushStyle::CreateStr2BrushStyle(); auto it = str2BrushStyle.find(str.toLatin1()); if (it != str2BrushStyle.end()) { return setValue(it.value(), reason); } return false; } bool QtnPropertyQBrushStyleBase::toStrImpl(QString &str) const { QByteArray id; if (!brushStyleToStr(value(), id)) return false; str = QString::fromLatin1(id.data(), id.size()); return true; } QDataStream &operator<<(QDataStream &stream, Qt::BrushStyle brushStyle) { stream << (qint32) brushStyle; return stream; } QDataStream &operator>>(QDataStream &stream, Qt::BrushStyle &brushStyle) { qint32 value = 0; stream >> value; brushStyle = (Qt::BrushStyle) value; return stream; } QtnPropertyQBrushStyleCallback::QtnPropertyQBrushStyleCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } ================================================ FILE: QtnProperty/GUI/PropertyQBrush.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_BRUSH_H #define PROPERTY_BRUSH_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include "QtnProperty/Enum.h" #include Q_DECLARE_METATYPE(Qt::BrushStyle) class QTN_IMPORT_EXPORT QtnPropertyQBrushStyleBase : public QtnSinglePropertyBase { Q_OBJECT QtnPropertyQBrushStyleBase( const QtnPropertyQBrushStyleBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQBrushStyleBase(QObject *parent); static bool brushStyleToStr(Qt::BrushStyle brushStyle, QByteArray &result); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyQBrushStyleBase) }; P_PROPERTY_DECL_EQ_OPERATORS(QtnPropertyQBrushStyleBase, Qt::BrushStyle) QTN_IMPORT_EXPORT QDataStream &operator<<( QDataStream &stream, Qt::BrushStyle brushStyle); QTN_IMPORT_EXPORT QDataStream &operator>>( QDataStream &stream, Qt::BrushStyle &brushStyle); class QTN_IMPORT_EXPORT QtnPropertyQBrushStyleCallback : public QtnSinglePropertyCallback { Q_OBJECT QtnPropertyQBrushStyleCallback( const QtnPropertyQBrushStyleCallback &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQBrushStyleCallback(QObject *parent); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQBrushStyleCallback, QtnPropertyQBrushStyleBase) }; class QTN_IMPORT_EXPORT QtnPropertyQBrushStyle : public QtnSinglePropertyValue { Q_OBJECT QtnPropertyQBrushStyle( const QtnPropertyQBrushStyle &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQBrushStyle(QObject *parent); static bool translateBrushStyle(Qt::BrushStyle brushStyle, QString &result); using StrBrushStyleMap = QMap; using BrushStyleToStrMap = QMap; static StrBrushStyleMap CreateStr2BrushStyle(); static BrushStyleToStrMap CreateBrushStyle2Str(); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQBrushStyle, QtnPropertyQBrushStyleBase) }; #endif // PROPERTY_BRUSH_H ================================================ FILE: QtnProperty/GUI/PropertyQColor.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQColor.h" #include "QtnProperty/Auxiliary/PropertyDelegateInfo.h" QtnPropertyQColorBase::QtnPropertyQColorBase(QObject *parent) : QtnStructPropertyBase(parent) { } QtnProperty *QtnPropertyQColorBase::createRedProperty() { auto result = createFieldProperty(&QColor::red, &QColor::setRed, QtnPropertyQColor::redKey(), QtnPropertyQColor::redDisplayName(), QtnPropertyQColor::redDescriptionFmt()); result->setMinValue(0); result->setMaxValue(255); QtnPropertyDelegateInfo delegate; delegate.name = qtnSliderBoxDelegate(); delegate.attributes[qtnLiveUpdateAttr()] = true; delegate.attributes[qtnAnimateAttr()] = true; delegate.attributes[qtnFillColorAttr()] = QColor(255, 100, 100); result->setDelegateInfo(delegate); return result; } QtnProperty *QtnPropertyQColorBase::createGreenProperty() { auto result = createFieldProperty(&QColor::green, &QColor::setGreen, QtnPropertyQColor::greenKey(), QtnPropertyQColor::greenDisplayName(), QtnPropertyQColor::greenDescriptionFmt()); result->setMinValue(0); result->setMaxValue(255); QtnPropertyDelegateInfo delegate; delegate.name = qtnSliderBoxDelegate(); delegate.attributes[qtnLiveUpdateAttr()] = true; delegate.attributes[qtnAnimateAttr()] = true; delegate.attributes[qtnFillColorAttr()] = QColor(100, 255, 100); result->setDelegateInfo(delegate); return result; } QtnProperty *QtnPropertyQColorBase::createBlueProperty() { auto result = createFieldProperty(&QColor::blue, &QColor::setBlue, QtnPropertyQColor::blueKey(), QtnPropertyQColor::blueDisplayName(), QtnPropertyQColor::blueDescriptionFmt()); result->setMinValue(0); result->setMaxValue(255); QtnPropertyDelegateInfo delegate; delegate.name = qtnSliderBoxDelegate(); delegate.attributes[qtnLiveUpdateAttr()] = true; delegate.attributes[qtnAnimateAttr()] = true; delegate.attributes[qtnFillColorAttr()] = QColor(100, 100, 255); result->setDelegateInfo(delegate); return result; } bool QtnPropertyQColorBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { QColor color; return QtnPropertyQColor::colorFromStr(str, color) && setValue(color, reason); } bool QtnPropertyQColorBase::toStrImpl(QString &str) const { return QtnPropertyQColor::strFromColor(value(), str); } bool QtnPropertyQColor::colorFromStr(const QString &str, QColor &color) { QColor newColor(str.trimmed()); if (!newColor.isValid()) return false; color = newColor; return true; } bool QtnPropertyQColor::strFromColor(const QColor &color, QString &str) { str = color.name((color.alpha() < 255) ? QColor::HexArgb : QColor::HexRgb); return true; } QtnPropertyQColorCallback::QtnPropertyQColorCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } QtnPropertyQColor::QtnPropertyQColor(QObject *parent) : QtnSinglePropertyValue(parent) { } QString QtnPropertyQColor::redKey() { return QStringLiteral("red"); } QString QtnPropertyQColor::redDisplayName() { return tr("Red"); } QString QtnPropertyQColor::redDescriptionFmt() { return tr("Red component of %1"); } QString QtnPropertyQColor::greenKey() { return QStringLiteral("green"); } QString QtnPropertyQColor::greenDisplayName() { return tr("Green"); } QString QtnPropertyQColor::greenDescriptionFmt() { return tr("Green component of %1"); } QString QtnPropertyQColor::blueKey() { return QStringLiteral("blue"); } QString QtnPropertyQColor::blueDisplayName() { return tr("Blue"); } QString QtnPropertyQColor::blueDescriptionFmt() { return tr("Blue component of %1"); } ================================================ FILE: QtnProperty/GUI/PropertyQColor.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_COLOR_H #define PROPERTY_COLOR_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include "QtnProperty/StructPropertyBase.h" #include "QtnProperty/Core/PropertyInt.h" #include enum QtnColorDelegateShape { QtnColorDelegateShapeNone = 0x1, QtnColorDelegateShapeSquare = 0x2, QtnColorDelegateShapeCircle = 0x3 }; class QTN_IMPORT_EXPORT QtnPropertyQColorBase : public QtnStructPropertyBase { Q_OBJECT private: QtnPropertyQColorBase(const QtnPropertyQColorBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQColorBase(QObject *parent); QtnProperty *createRedProperty(); QtnProperty *createGreenProperty(); QtnProperty *createBlueProperty(); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyQColorBase) }; P_PROPERTY_DECL_EQ_OPERATORS(QtnPropertyQColorBase, QColor) class QTN_IMPORT_EXPORT QtnPropertyQColorCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyQColorCallback( const QtnPropertyQColorCallback &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQColorCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQColorCallback, QtnPropertyQColorBase) }; class QTN_IMPORT_EXPORT QtnPropertyQColor : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyQColor(const QtnPropertyQColor &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQColor(QObject *parent = nullptr); static QString redKey(); static QString redDisplayName(); static QString redDescriptionFmt(); static QString greenKey(); static QString greenDisplayName(); static QString greenDescriptionFmt(); static QString blueKey(); static QString blueDisplayName(); static QString blueDescriptionFmt(); static bool colorFromStr(const QString &str, QColor &color); static bool strFromColor(const QColor &color, QString &str); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyQColor, QtnPropertyQColorBase) }; #endif // PROPERTY_COLOR_H ================================================ FILE: QtnProperty/GUI/PropertyQFont.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQFont.h" #include QtnPropertyQFontBase::QtnPropertyQFontBase(QObject *parent) : QtnSinglePropertyBase(parent) { } bool QtnPropertyQFontBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { QFont font; if (!font.fromString(str.trimmed())) return false; return setValue(font, reason); } bool QtnPropertyQFontBase::toStrImpl(QString &str) const { QFont v = value(); str = v.toString(); return true; } QtnPropertyQFont::QtnPropertyQFont(QObject *parent) : QtnSinglePropertyValue(parent) { } QString QtnPropertyQFont::getPixelStr() { return tr("Pixel"); } QString QtnPropertyQFont::getPointStr() { return tr("Point"); } QString QtnPropertyQFont::getPreferDefaultStr() { return tr("PreferDefault"); } QString QtnPropertyQFont::getNoAntialiasStr() { return tr("NoAntialias"); } QString QtnPropertyQFont::getPreferAntialiasStr() { return tr("PreferAntialias"); } QString QtnPropertyQFont::getFamilyLabel() { return tr("Family"); } QString QtnPropertyQFont::getFamilyDescription(const QString &ownerName) { return tr("Family for %1").arg(ownerName); } QString QtnPropertyQFont::getStyleLabel() { return tr("Style"); } QString QtnPropertyQFont::getStyleDescription(const QString &ownerName) { return tr("Style for %1").arg(ownerName); } QString QtnPropertyQFont::getSizeLabel() { return tr("Size"); } QString QtnPropertyQFont::getSizeDescription(const QString &ownerName) { return tr("Size for %1").arg(ownerName); } QString QtnPropertyQFont::getSizeUnitLabel() { return tr("Size Unit"); } QString QtnPropertyQFont::getSizeUnitDescription(const QString &ownerName) { return tr("Size Unit for %1").arg(ownerName); } QString QtnPropertyQFont::getBoldLabel() { return tr("Bold"); } QString QtnPropertyQFont::getBoldDescription(const QString &ownerName) { return tr("Bold flag for %1").arg(ownerName); } QString QtnPropertyQFont::getItalicLabel() { return tr("Italic"); } QString QtnPropertyQFont::getItalicDescription(const QString &ownerName) { return tr("Italic flag for %1").arg(ownerName); } QString QtnPropertyQFont::getUnderlineLabel() { return tr("Underline"); } QString QtnPropertyQFont::getUnderlineDescription(const QString &ownerName) { return tr("Underline flag for %1").arg(ownerName); } QString QtnPropertyQFont::getStrikeoutLabel() { return tr("Strikeout"); } QString QtnPropertyQFont::getStrikeoutDescription(const QString &ownerName) { return tr("Strikeout flag for %1").arg(ownerName); } QString QtnPropertyQFont::getKerningLabel() { return tr("Kerning"); } QString QtnPropertyQFont::getKerningDescription(const QString &ownerName) { return tr("Kerning flag for %1").arg(ownerName); } QString QtnPropertyQFont::getAntialiasingLabel() { return tr("Antialiasing"); } QString QtnPropertyQFont::getAntialiasingDescription(const QString &ownerName) { return tr("Antialiasing options for %1").arg(ownerName); } QtnPropertyQFontCallback::QtnPropertyQFontCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } ================================================ FILE: QtnProperty/GUI/PropertyQFont.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_FONT_H #define PROPERTY_FONT_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include class QTN_IMPORT_EXPORT QtnPropertyQFontBase : public QtnSinglePropertyBase { Q_OBJECT private: QtnPropertyQFontBase(const QtnPropertyQFontBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQFontBase(QObject *parent); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyQFontBase) }; P_PROPERTY_DECL_EQ_OPERATORS(QtnPropertyQFontBase, QFont) class QTN_IMPORT_EXPORT QtnPropertyQFontCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyQFontCallback( const QtnPropertyQFontCallback &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQFontCallback(QObject *parent); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQFontCallback, QtnPropertyQFontBase) }; class QTN_IMPORT_EXPORT QtnPropertyQFont : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyQFont(const QtnPropertyQFont &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQFont(QObject *parent); static QString getPixelStr(); static QString getPointStr(); static QString getPreferDefaultStr(); static QString getNoAntialiasStr(); static QString getPreferAntialiasStr(); static QString getFamilyLabel(); static QString getFamilyDescription(const QString &ownerName); static QString getStyleLabel(); static QString getStyleDescription(const QString &ownerName); static QString getSizeLabel(); static QString getSizeDescription(const QString &ownerName); static QString getSizeUnitLabel(); static QString getSizeUnitDescription(const QString &ownerName); static QString getBoldLabel(); static QString getBoldDescription(const QString &ownerName); static QString getItalicLabel(); static QString getItalicDescription(const QString &ownerName); static QString getUnderlineLabel(); static QString getUnderlineDescription(const QString &ownerName); static QString getStrikeoutLabel(); static QString getStrikeoutDescription(const QString &ownerName); static QString getKerningLabel(); static QString getKerningDescription(const QString &ownerName); static QString getAntialiasingLabel(); static QString getAntialiasingDescription(const QString &ownerName); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyQFont, QtnPropertyQFontBase) }; #endif // PROPERTY_FONT_H ================================================ FILE: QtnProperty/GUI/PropertyQPen.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQPen.h" #include "QtnProperty/GUI/PropertyQColor.h" #include #include #include static const char *TRANSLATIONS[] = { QT_TRANSLATE_NOOP("Qt", "NoPen"), QT_TRANSLATE_NOOP("Qt", "SolidLine"), QT_TRANSLATE_NOOP("Qt", "DashLine"), QT_TRANSLATE_NOOP("Qt", "DotLine"), QT_TRANSLATE_NOOP("Qt", "DashDotLine"), QT_TRANSLATE_NOOP("Qt", "DashDotDotLine"), QT_TRANSLATE_NOOP("Qt", "CustomDashLine"), QT_TRANSLATE_NOOP("Qt", "FlatCap"), QT_TRANSLATE_NOOP("Qt", "SquareCap"), QT_TRANSLATE_NOOP("Qt", "RoundCap"), QT_TRANSLATE_NOOP("Qt", "MiterJoin"), QT_TRANSLATE_NOOP("Qt", "BevelJoin"), QT_TRANSLATE_NOOP("Qt", "RoundJoin"), QT_TRANSLATE_NOOP("Qt", "SvgMiterJoin"), }; QtnPropertyQPenStyleBase::QtnPropertyQPenStyleBase(QObject *parent) : QtnSinglePropertyBase(parent) { Q_UNUSED(TRANSLATIONS); } bool QtnPropertyQPenStyleBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { auto metaEnum = QMetaEnum::fromType(); bool ok = false; int value = metaEnum.keyToValue(str.toLatin1(), &ok); if (ok) { setValue(Qt::PenStyle(value), reason); return true; } return false; } bool QtnPropertyQPenStyleBase::toStrImpl(QString &str) const { auto metaEnum = QMetaEnum::fromType(); auto key = metaEnum.valueToKey(int(value())); if (key) { str = QLatin1String(key); return true; } return false; } QDataStream &operator<<(QDataStream &stream, Qt::PenStyle penStyle) { stream << (qint32) penStyle; return stream; } QDataStream &operator>>(QDataStream &stream, Qt::PenStyle &penStyle) { qint32 value = 0; stream >> value; penStyle = (Qt::PenStyle) value; return stream; } QtnPropertyQPenBase::QtnPropertyQPenBase(QObject *parent) : QtnSinglePropertyBase(parent) { } const QtnEnumInfo &QtnPropertyQPenBase::penStyleEnum() { static QtnEnumInfo enumInfo; if (!enumInfo.isValid()) { enumInfo = QtnEnumInfo::withEnum(true); auto &vec = enumInfo.getVector(); for (auto it = vec.begin(); it != vec.end(); ++it) { if (it->value() == Qt::MPenStyle) { vec.erase(it); break; } } } return enumInfo; } const QtnEnumInfo &QtnPropertyQPenBase::penCapStyleEnum() { static QtnEnumInfo enumInfo; if (!enumInfo.isValid()) { enumInfo = QtnEnumInfo::withEnum(true); auto &vec = enumInfo.getVector(); for (auto it = vec.begin(); it != vec.end(); ++it) { if (it->value() == Qt::MPenCapStyle) { vec.erase(it); break; } } } return enumInfo; } const QtnEnumInfo &QtnPropertyQPenBase::penJoinStyleEnum() { static QtnEnumInfo enumInfo; if (!enumInfo.isValid()) { enumInfo = QtnEnumInfo::withEnum(true); auto &vec = enumInfo.getVector(); for (auto it = vec.begin(); it != vec.end(); ++it) { if (it->value() == Qt::MPenJoinStyle) { vec.erase(it); break; } } } return enumInfo; } bool QtnPropertyQPenBase::penFromStr(const QString &str, QPen &pen) { QStringList penParts = str.split(','); if (penParts.size() != 5) return false; QColor color; if (!QtnPropertyQColor::colorFromStr(penParts[0], color)) return false; auto styleEnum = penStyleEnum().fromStr(penParts[1]); if (!styleEnum) return false; auto style = Qt::PenStyle(styleEnum->value()); bool ok = false; int width = penParts[2].trimmed().toInt(&ok); if (!ok) return false; auto capStyleEnum = penCapStyleEnum().fromStr(penParts[3]); if (!capStyleEnum) return false; auto capStyle = Qt::PenCapStyle(capStyleEnum->value()); auto joinStyleEnum = penJoinStyleEnum().fromStr(penParts[4]); if (!joinStyleEnum) return false; auto joinStyle = Qt::PenJoinStyle(joinStyleEnum->value()); pen.setColor(color); pen.setStyle(style); pen.setWidth(width); pen.setCapStyle(capStyle); pen.setJoinStyle(joinStyle); return true; } bool QtnPropertyQPenBase::strFromPen(const QPen &pen, QString &str) { QString color; QtnPropertyQColor::strFromColor(pen.color(), color); QString style; penStyleEnum().toStr(style, pen.style()); QString width = QString::number(pen.width()); QString capStyle; penCapStyleEnum().toStr(capStyle, pen.capStyle()); QString joinStyle; penJoinStyleEnum().toStr(joinStyle, pen.joinStyle()); str = QString("%1, %2, %3, %4, %5") .arg(color, style, width, capStyle, joinStyle); return true; } bool QtnPropertyQPenBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { QPen pen; if (!penFromStr(str, pen)) return false; return setValue(pen, reason); } bool QtnPropertyQPenBase::toStrImpl(QString &str) const { return strFromPen(value(), str); } bool QtnPropertyQPenBase::fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) { if (!var.canConvert()) return false; setValue(var.value(), reason); return true; } bool QtnPropertyQPenBase::toVariantImpl(QVariant &var) const { var = QVariant::fromValue(value()); return true; } QtnPropertyQPenStyleCallback::QtnPropertyQPenStyleCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } QtnPropertyQPenStyle::QtnPropertyQPenStyle(QObject *parent) : QtnSinglePropertyValue(parent) { } QtnPropertyQPenCallback::QtnPropertyQPenCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } QtnPropertyQPen::QtnPropertyQPen(QObject *parent) : QtnSinglePropertyValue(parent) { } QString QtnPropertyQPen::rootDisplayValue() { return tr("(Pen)"); } QString QtnPropertyQPen::colorKey() { return QStringLiteral("color"); } QString QtnPropertyQPen::colorDisplayName() { return tr("Color"); } QString QtnPropertyQPen::colorDescriptionFmt() { return tr("Color of the %1"); } QString QtnPropertyQPen::styleKey() { return QStringLiteral("style"); } QString QtnPropertyQPen::styleDisplayName() { return tr("Style"); } QString QtnPropertyQPen::styleDescriptionFmt() { return tr("Style of the %1"); } QString QtnPropertyQPen::capStyleKey() { return QStringLiteral("capStyle"); } QString QtnPropertyQPen::capStyleDisplayName() { return tr("Cap Style"); } QString QtnPropertyQPen::capStyleDescriptionFmt() { return tr("Cap Style of the %1"); } QString QtnPropertyQPen::joinStyleKey() { return QStringLiteral("joinStyle"); } QString QtnPropertyQPen::joinStyleDisplayName() { return tr("Join Style"); } QString QtnPropertyQPen::joinStyleDescriptionFmt() { return tr("Join Style of the %1"); } ================================================ FILE: QtnProperty/GUI/PropertyQPen.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTY_PEN_H #define PROPERTY_PEN_H #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include "QtnProperty/Enum.h" #include "QtnProperty/StructPropertyBase.h" #include Q_DECLARE_METATYPE(Qt::PenStyle) class QTN_IMPORT_EXPORT QtnPropertyQPenStyleBase : public QtnSinglePropertyBase { Q_OBJECT QtnPropertyQPenStyleBase( const QtnPropertyQPenStyleBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQPenStyleBase(QObject *parent); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyQPenStyleBase) }; P_PROPERTY_DECL_EQ_OPERATORS(QtnPropertyQPenStyleBase, Qt::PenStyle) QTN_IMPORT_EXPORT QDataStream &operator<<( QDataStream &stream, Qt::PenStyle penStyle); QTN_IMPORT_EXPORT QDataStream &operator>>( QDataStream &stream, Qt::PenStyle &penStyle); class QTN_IMPORT_EXPORT QtnPropertyQPenStyleCallback : public QtnSinglePropertyCallback { Q_OBJECT QtnPropertyQPenStyleCallback( const QtnPropertyQPenStyleCallback &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQPenStyleCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQPenStyleCallback, QtnPropertyQPenStyleBase) }; class QTN_IMPORT_EXPORT QtnPropertyQPenStyle : public QtnSinglePropertyValue { Q_OBJECT QtnPropertyQPenStyle(const QtnPropertyQPenStyle &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQPenStyle(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQPenStyle, QtnPropertyQPenStyleBase) }; class QTN_IMPORT_EXPORT QtnPropertyQPenBase : public QtnSinglePropertyBase { Q_OBJECT QtnPropertyQPenBase(const QtnPropertyQPenBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQPenBase(QObject *parent); QtnProperty *createPenStyleProperty(); QtnProperty *createCapStyleProperty(); QtnProperty *createJoinStyleProperty(); static const QtnEnumInfo &penStyleEnum(); static const QtnEnumInfo &penCapStyleEnum(); static const QtnEnumInfo &penJoinStyleEnum(); static bool penFromStr(const QString &str, QPen &pen); static bool strFromPen(const QPen &pen, QString &str); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; // variant conversion implementation bool fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) override; bool toVariantImpl(QVariant &var) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyQPenBase) }; P_PROPERTY_DECL_EQ_OPERATORS(QtnPropertyQPenBase, QPen) class QTN_IMPORT_EXPORT QtnPropertyQPenCallback : public QtnSinglePropertyCallback { Q_OBJECT QtnPropertyQPenCallback( const QtnPropertyQPenCallback &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQPenCallback(QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQPenCallback, QtnPropertyQPenBase) }; class QTN_IMPORT_EXPORT QtnPropertyQPen : public QtnSinglePropertyValue { Q_OBJECT QtnPropertyQPen(const QtnPropertyQPen &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQPen(QObject *parent = nullptr); static QString rootDisplayValue(); static QString colorKey(); static QString colorDisplayName(); static QString colorDescriptionFmt(); static QString styleKey(); static QString styleDisplayName(); static QString styleDescriptionFmt(); static QString capStyleKey(); static QString capStyleDisplayName(); static QString capStyleDescriptionFmt(); static QString joinStyleKey(); static QString joinStyleDisplayName(); static QString joinStyleDescriptionFmt(); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyQPen, QtnPropertyQPenBase) }; #endif // PROPERTY_PEN_H ================================================ FILE: QtnProperty/GUI/PropertyQVector3D.cpp ================================================ /******************************************************************************* Copyright (c) 2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQVector3D.h" #include "QtnProperty/Core/PropertyQPoint.h" QtnPropertyQVector3DBase::QtnPropertyQVector3DBase(QObject *parent) : ParentClass(parent) { } QtnProperty *QtnPropertyQVector3DBase::createXProperty() { return createFieldProperty(&QVector3D::x, &QVector3D::setX, QtnPropertyQPoint::xKey(), QtnPropertyQPoint::xDisplayName(), QtnPropertyQPoint::xDescriptionFmt()); } QtnProperty *QtnPropertyQVector3DBase::createYProperty() { return createFieldProperty(&QVector3D::y, &QVector3D::setY, QtnPropertyQPoint::yKey(), QtnPropertyQPoint::yDisplayName(), QtnPropertyQPoint::yDescriptionFmt()); } QtnProperty *QtnPropertyQVector3DBase::createZProperty() { return createFieldProperty(&QVector3D::z, &QVector3D::setZ, QtnPropertyQVector3D::zKey(), QtnPropertyQVector3D::zDisplayName(), QtnPropertyQVector3D::zDescriptionFmt()); } static const auto sPrefix = QStringLiteral("QVector3D"); bool QtnPropertyQVector3DBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { auto text = str.trimmed(); if (!text.startsWith(sPrefix, Qt::CaseInsensitive)) { return false; } text = text.mid(sPrefix.length()).trimmed(); if (!text.startsWith(QChar('(')) || !text.endsWith(QChar(')'))) { return false; } text = text.mid(1, text.length() - 2).trimmed(); auto params = text.split(QChar(',')); if (params.size() != 3) { return false; } bool ok = false; float x = params.at(0).trimmed().toFloat(&ok); if (!ok) return false; float y = params.at(1).trimmed().toFloat(&ok); if (!ok) return false; float z = params.at(2).trimmed().toFloat(&ok); if (!ok) return false; return setValue(QVector3D(x, y, z), reason); } bool QtnPropertyQVector3DBase::toStrImpl(QString &str) const { QVector3D v = value(); str = QStringLiteral("%1(%2, %3, %4)") .arg(sPrefix) .arg(v.x()) .arg(v.y()) .arg(v.z()); return true; } QtnPropertyQVector3D::QtnPropertyQVector3D(QObject *parent) : QtnSinglePropertyValue(parent) { } QString QtnPropertyQVector3D::zKey() { return QStringLiteral("z"); } QString QtnPropertyQVector3D::zDisplayName() { return tr("Z"); } QString QtnPropertyQVector3D::zDescriptionFmt() { return tr("Z of the %1"); } QString QtnPropertyQVector3D::getToStringFormat() { return tr("[%1, %2, %3]"); } QtnPropertyQVector3DCallback::QtnPropertyQVector3DCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } ================================================ FILE: QtnProperty/GUI/PropertyQVector3D.h ================================================ /******************************************************************************* Copyright (c) 2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "QtnProperty/Auxiliary/PropertyTemplates.h" #include "QtnProperty/Core/PropertyFloat.h" #include "QtnProperty/StructPropertyBase.h" #include class QTN_IMPORT_EXPORT QtnPropertyQVector3DBase : public QtnStructPropertyBase { Q_OBJECT private: QtnPropertyQVector3DBase( const QtnPropertyQVector3DBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQVector3DBase(QObject *parent); QtnProperty *createXProperty(); QtnProperty *createYProperty(); QtnProperty *createZProperty(); protected: // string conversion implementation bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; bool toStrImpl(QString &str) const override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyQVector3DBase) }; P_PROPERTY_DECL_EQ_OPERATORS(QtnPropertyQVector3DBase, QVector3D) class QTN_IMPORT_EXPORT QtnPropertyQVector3DCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyQVector3DCallback( const QtnPropertyQVector3DCallback &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQVector3DCallback( QObject *parent = nullptr); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQVector3DCallback, QtnPropertyQVector3DBase) }; class QTN_IMPORT_EXPORT QtnPropertyQVector3D : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyQVector3D(const QtnPropertyQVector3D &other) Q_DECL_EQ_DELETE; public: Q_INVOKABLE explicit QtnPropertyQVector3D(QObject *parent = nullptr); static QString zKey(); static QString zDisplayName(); static QString zDescriptionFmt(); static QString getToStringFormat(); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyQVector3D, QtnPropertyQVector3DBase) }; ================================================ FILE: QtnProperty/IQtnPropertyStateProvider.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "Auxiliary/PropertyAux.h" struct IQtnPropertyStateProvider { virtual ~IQtnPropertyStateProvider() {} virtual QtnPropertyState getPropertyState( const QMetaProperty &metaProperty) const = 0; virtual void setPropertyState( const QMetaProperty &metaProperty, QtnPropertyState state) = 0; }; ================================================ FILE: QtnProperty/Install.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "Install.h" #include "PropertyInt64.h" #include "PropertyUInt64.h" #include "PropertyQVariant.h" #include "PropertyQKeySequence.h" #include "Delegates/Core/PropertyDelegateBool.h" #include "Delegates/Core/PropertyDelegateDouble.h" #include "Delegates/Core/PropertyDelegateFloat.h" #include "Delegates/Core/PropertyDelegateInt.h" #include "Delegates/Core/PropertyDelegateUInt.h" #include "Delegates/Core/PropertyDelegateEnum.h" #include "Delegates/Core/PropertyDelegateEnumFlags.h" #include "Delegates/Core/PropertyDelegateQPoint.h" #include "Delegates/Core/PropertyDelegateQRect.h" #include "Delegates/Core/PropertyDelegateQSize.h" #include "Delegates/Core/PropertyDelegateQString.h" #include "Delegates/Core/PropertyDelegateQPointF.h" #include "Delegates/Core/PropertyDelegateQSizeF.h" #include "Delegates/Core/PropertyDelegateQRectF.h" #include "Delegates/GUI/PropertyDelegateQColor.h" #include "Delegates/GUI/PropertyDelegateQFont.h" #include "Delegates/GUI/PropertyDelegateQPen.h" #include "Delegates/GUI/PropertyDelegateQBrush.h" #include "Delegates/GUI/PropertyDelegateQVector3D.h" #include "MultiProperty.h" #include "QObjectPropertySet.h" #include "Utils/AccessibilityProxy.h" #include #include #include #include template static QtnProperty *createRealNumberProperty( QObject *object, const QMetaProperty &metaProperty) { using ValueTypeStore = typename QtnPropertyRealCallback::ValueTypeStore; auto property = new QtnPropertyRealCallback(nullptr); switch (metaProperty.revision()) { case PERCENT_SUFFIX: { QtnPropertyDelegateInfo delegate; qtnInitPercentSpinBoxDelegate(delegate); property->setDelegateInfo(delegate); property->setCallbackValueGet( [object, metaProperty]() -> ValueTypeStore { return ValueTypeStore( metaProperty.read(object).toDouble() * 100.0); }); property->setCallbackValueSet( [object, metaProperty]( ValueTypeStore value, QtnPropertyChangeReason /*reason*/) { metaProperty.write(object, value / ValueTypeStore(100.0)); }); return property; } case DEGREE_SUFFIX: { QtnPropertyDelegateInfo delegate; qtnInitDegreeSpinBoxDelegate(delegate); property->setDelegateInfo(delegate); break; } } property->setCallbackValueGet([object, metaProperty]() -> ValueTypeStore { return ValueTypeStore(metaProperty.read(object).toDouble()); }); property->setCallbackValueSet([object, metaProperty](ValueTypeStore value, QtnPropertyChangeReason /*reason*/) { metaProperty.write(object, value); }); return property; } static void qtnRegisterDefaultMetaPropertyFactory() { qtnRegisterMetaPropertyFactory( QMetaType::Bool, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::QString, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::Double, createRealNumberProperty); qtnRegisterMetaPropertyFactory( QMetaType::Float, createRealNumberProperty); qtnRegisterMetaPropertyFactory( QMetaType::Int, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::UInt, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::LongLong, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::ULongLong, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::QPoint, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::QPointF, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::QRect, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::QRectF, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::QSize, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::QSizeF, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::QColor, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::QFont, qtnCreateFactory()); qtnRegisterMetaPropertyFactory( QMetaType::QPen, qtnCreateFactory()); qtnRegisterMetaPropertyFactory(qMetaTypeId(), qtnCreateFactory()); qtnRegisterMetaPropertyFactory(qMetaTypeId(), qtnCreateFactory()); qtnRegisterMetaPropertyFactory(qMetaTypeId(), qtnCreateFactory()); qtnRegisterMetaPropertyFactory(QMetaType::QVariant, [](QObject *object, const QMetaProperty &metaProperty) -> QtnProperty * { return new QtnPropertyQVariantCallback(object, metaProperty); }); qtnRegisterMetaPropertyFactory(QMetaType::QKeySequence, qtnCreateFactory()); } bool qtnPropertyRegister() { Q_INIT_RESOURCE(QtnProperty); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qtnRegisterDefaultMetaPropertyFactory(); return true; } void qtnPropertyInstallTranslations(const QLocale &locale) { static QTranslator translator; QCoreApplication::removeTranslator(&translator); if (translator.load(locale, "QtnProperty.qm", "", ":/Translations")) { QCoreApplication::installTranslator(&translator); } } ================================================ FILE: QtnProperty/Install.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "Config.h" class QLocale; QTN_IMPORT_EXPORT void qtnPropertyInstallTranslations(const QLocale &locale); ================================================ FILE: QtnProperty/MultiProperty.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "MultiProperty.h" #include "Install.h" #include "Property.h" #include "PropertySet.h" #include "PropertyConnector.h" #include "Delegates/PropertyDelegateFactory.h" #include "Utils/QtnConnections.h" #include #include #include struct QtnMultiPropertyDelegate::PropertyToEdit { QtnMultiProperty *owner; QtnProperty *property; QtnConnections connections; }; QtnMultiProperty::QtnMultiProperty( const QMetaObject *propertyMetaObject, QObject *parent) : QtnProperty(parent) , mPropertyMetaObject(propertyMetaObject) , m_subPropertyUpdates(0) , edited(false) , calculateMultipleValues(true) , multipleValues(false) { setDelegateInfo(QtnPropertyDelegateInfo()); } QtnMultiProperty::~QtnMultiProperty() { for (auto property : properties) { QObject::disconnect(property, &QtnProperty::propertyValueAccept, this, &QtnMultiProperty::onPropertyValueAccept); QObject::disconnect(property, &QtnPropertyBase::propertyWillChange, this, &QtnMultiProperty::onPropertyWillChange); QObject::disconnect(property, &QtnPropertyBase::propertyDidChange, this, &QtnMultiProperty::onPropertyDidChange); } } const QMetaObject *QtnMultiProperty::propertyMetaObject() const { return mPropertyMetaObject; } void QtnMultiProperty::addProperty(QtnProperty *property, bool own) { Q_ASSERT(nullptr != property); Q_ASSERT(nullptr != mPropertyMetaObject->cast(property)); if (own) property->setParent(this); if (properties.end() != std::find(properties.begin(), properties.end(), property)) { return; } properties.push_back(property); if (property->isCollapsed()) collapse(); updateStateFrom(property); QObject::connect(property, &QtnProperty::propertyValueAccept, this, &QtnMultiProperty::onPropertyValueAccept); QObject::connect(property, &QtnPropertyBase::propertyWillChange, this, &QtnMultiProperty::onPropertyWillChange); QObject::connect(property, &QtnPropertyBase::propertyDidChange, this, &QtnMultiProperty::onPropertyDidChange); } void QtnMultiProperty::doReset(QtnPropertyChangeReason reason) { Q_ASSERT(reason & QtnPropertyChangeReasonResetValue); m_subPropertyUpdates++; emit propertyWillChange(reason, nullptr, 0); for (auto property : properties) { property->reset(reason); } emit propertyDidChange(reason); m_subPropertyUpdates--; updateMultipleState(true); } QString QtnMultiProperty::getMultiValuePlaceholder() { return tr("(Multiple Values)"); } QMetaProperty QtnMultiProperty::getMetaProperty() const { Q_ASSERT(!properties.empty()); auto connector = properties.at(0)->getConnector(); Q_ASSERT(nullptr != connector); return connector->getMetaProperty(); } bool QtnMultiProperty::hasMultipleValues() const { if (calculateMultipleValues) { QString dummy; toStrImpl(dummy); } return multipleValues; } void QtnMultiProperty::onPropertyValueAccept( QtnPropertyValuePtr valueToAccept, bool *accept) { if (m_subPropertyUpdates) return; emit propertyValueAccept(valueToAccept, accept); } void QtnMultiProperty::onPropertyWillChange( QtnPropertyChangeReason reason, QtnPropertyValuePtr newValue, int typeId) { if (m_subPropertyUpdates) return; emit propertyWillChange(reason, newValue, typeId); } void QtnMultiProperty::onPropertyDidChange(QtnPropertyChangeReason reason) { if (m_subPropertyUpdates) return; Q_ASSERT(nullptr != qobject_cast(sender())); auto changedProperty = static_cast(sender()); if (edited && (reason & QtnPropertyChangeReasonEdit) && (reason & QtnPropertyChangeReasonValue)) { auto value = changedProperty->valueAsVariant(); auto singleReason = reason & ~QtnPropertyChangeReasonMultiEdit; m_subPropertyUpdates++; for (auto property : properties) { if (property != changedProperty && property->isEditableByUser()) { property->fromVariant(value, singleReason); } } m_subPropertyUpdates--; } if (reason & (QtnPropertyChangeReasonState | QtnPropertyChangeReasonValue)) { updateStateFrom(changedProperty); updateMultipleState(true); } emit propertyDidChange(reason); } void QtnMultiProperty::updatePropertyState() { QtnProperty::updatePropertyState(); if (m_subPropertyUpdates) { return; } if (!stateLocal().testFlag(QtnPropertyStateUnlockable)) { return; } bool isImmutable = stateLocal().testFlag(QtnPropertyStateImmutable); m_subPropertyUpdates++; for (auto property : properties) { if (property->stateLocal().testFlag(QtnPropertyStateUnlockable)) { property->switchState(QtnPropertyStateImmutable, isImmutable); } } m_subPropertyUpdates--; } bool QtnMultiProperty::loadImpl(QDataStream &stream) { for (auto property : properties) { QByteArray propertyData; stream >> propertyData; QDataStream propertyStream(&propertyData, QIODevice::ReadOnly); if (!property->load(propertyStream)) return false; } return true; } bool QtnMultiProperty::saveImpl(QDataStream &stream) const { for (auto property : properties) { QByteArray propertyData; QDataStream propertyStream(&propertyData, QIODevice::WriteOnly); if (!property->save(propertyStream)) return false; stream << propertyData; } return true; } void QtnMultiProperty::masterPropertyWillChange(QtnPropertyChangeReason reason) { if (m_subPropertyUpdates) return; QtnProperty::masterPropertyWillChange(reason); } void QtnMultiProperty::masterPropertyDidChange(QtnPropertyChangeReason reason) { if (m_subPropertyUpdates) return; if (reason & (QtnPropertyChangeReasonState | QtnPropertyChangeReasonValue)) { updateMultipleState(true); } QtnProperty::masterPropertyDidChange(reason); } bool QtnMultiProperty::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { m_subPropertyUpdates++; emit propertyWillChange(reason, nullptr, 0); int okCount = 0; for (auto property : properties) { if (property->fromStr(str, reason)) okCount++; } emit propertyDidChange(reason); m_subPropertyUpdates--; return okCount > 0; } bool QtnMultiProperty::toStrImpl(QString &str) const { if (calculateMultipleValues) { auto thiz = const_cast(this); thiz->calculateMultipleValues = false; size_t sameCount = 0; QString temp; for (auto property : properties) { if (!property->toStr(str)) str.clear(); if (sameCount == 0) temp = str; if (sameCount == 0 || str == temp) sameCount++; } thiz->multipleValues = (sameCount != properties.size()); } else if (!multipleValues) { if (properties.empty() || !properties.at(0)->toStr(str)) str.clear(); } if (multipleValues) str.clear(); return true; } bool QtnMultiProperty::fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) { int okCount = 0; m_subPropertyUpdates++; emit propertyWillChange(reason, nullptr, 0); if (var.userType() == qMetaTypeId()) { auto values = var.value().values; auto count = properties.size(); auto varCount = size_t(values.count()); if (count > varCount) count = varCount; for (size_t i = 0; i < count; i++) { QtnProperty *property = properties.at(i); if (property->fromVariant(values.at(int(i)), reason)) okCount++; } } else { for (auto property : properties) { if (property->fromVariant(var, reason)) okCount++; } } emit propertyDidChange(reason); m_subPropertyUpdates--; return okCount > 0; } bool QtnMultiProperty::toVariantImpl(QVariant &var) const { QtnMultiVariant multiVariant; for (auto property : properties) { if (!property->toVariant(var)) var.clear(); multiVariant.values.push_back(var); } var.setValue(multiVariant); return true; } void QtnMultiProperty::updateStateFrom(QtnProperty *source) { static const QtnPropertyState unchangedState(QtnPropertyStateMultiValue | QtnPropertyStateCollapsed | QtnPropertyStateModifiedValue); auto state = stateLocal() & unchangedState; state |= source->stateLocal() & ~unchangedState; state &= ~(QtnPropertyStateImmutable | QtnPropertyStateResettable | QtnPropertyStateInvisible | QtnPropertyStateUnlockable); size_t unlockableCount = 0; for (auto property : properties) { auto childState = property->stateLocal(); if (childState.testFlag(QtnPropertyStateInvisible)) { state |= QtnPropertyStateInvisible; } if (childState.testFlag(QtnPropertyStateImmutable)) { state |= QtnPropertyStateImmutable; } if (childState.testFlag(QtnPropertyStateResettable)) { state |= QtnPropertyStateResettable; } if (childState.testFlag(QtnPropertyStateUnlockable)) { unlockableCount++; } } if (unlockableCount == properties.size()) { state |= QtnPropertyStateUnlockable; } m_subPropertyUpdates++; setState(state); m_subPropertyUpdates--; } void QtnMultiProperty::updateMultipleState(bool force) { if (force) calculateMultipleValues = true; bool multipleValues = hasMultipleValues(); auto state = stateLocal() & ~QtnPropertyStateModifiedValue; state.setFlag(QtnPropertyStateMultiValue, multipleValues); for (auto property : properties) { if (!property->valueIsDefault()) { state |= QtnPropertyStateModifiedValue; break; } } m_subPropertyUpdates++; setState(state); m_subPropertyUpdates--; } QtnMultiPropertyDelegate::QtnMultiPropertyDelegate(QtnMultiProperty &owner) : Inherited(owner) { owner.updateMultipleState(true); } void QtnMultiPropertyDelegate::init() { Q_ASSERT(superDelegates.empty()); auto &properties = owner().properties; superDelegates.reserve(properties.size()); for (auto property : properties) { auto delegate = factory()->createDelegate(*property); delegate->setStateProperty(&owner()); superDelegates.emplace_back(delegate); } } QtnMultiPropertyDelegate::~QtnMultiPropertyDelegate() { m_subProperties.clear(); } void QtnMultiPropertyDelegate::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnMultiProperty::staticMetaObject, &qtnCreateDelegate, "MultiProperty"); } void QtnMultiPropertyDelegate::onEditedPropertyDestroyed(PropertyToEdit *data) { Q_ASSERT(nullptr != data); data->owner = nullptr; data->property = nullptr; data->connections.clear(); } void QtnMultiPropertyDelegate::onEditorDestroyed(PropertyToEdit *data) { auto multiProperty = data->owner; if (multiProperty) { multiProperty->edited = false; } delete data; } void QtnMultiPropertyDelegate::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { for (auto &delegate : superDelegates) { QtnPropertyDelegateInfo mergedInfo; mergedInfo.attributes = info.attributes; auto delegateInfoPtr = delegate->propertyImmutable()->delegateInfo(); if (delegateInfoPtr) { mergedInfo.name = delegateInfoPtr->name; auto &attributes = delegateInfoPtr->attributes; for (auto it = attributes.cbegin(); it != attributes.cend(); ++it) { auto rootIt = mergedInfo.attributes.find(it.key()); if (rootIt != mergedInfo.attributes.end()) continue; mergedInfo.attributes[it.key()] = it.value(); } } delegate->applyAttributes(mergedInfo); for (int i = 0, count = delegate->subPropertyCount(); i < count; ++i) { auto property = delegate->subProperty(i); auto it = std::find_if(m_subProperties.begin(), m_subProperties.end(), [property](const QScopedPointer &a) -> bool { return property->propertyMetaObject() == a->propertyMetaObject() && property->displayName() == a->displayName(); }); auto subSet = property->asPropertySet(); if (subSet) { QtnPropertySet *multiSet; if (it == m_subProperties.end()) { multiSet = new QtnPropertySet( subSet->childrenOrder(), subSet->compareFunc()); multiSet->setName(subSet->name()); multiSet->setDisplayName(subSet->displayName()); multiSet->setDescription(subSet->description()); multiSet->setId(subSet->id()); multiSet->setState(subSet->stateLocal()); addSubProperty(multiSet); } else { multiSet = it->data()->asPropertySet(); } qtnPropertiesToMultiSet(multiSet, subSet, false); } else { QtnMultiProperty *multiProperty; if (it == m_subProperties.end()) { multiProperty = new QtnMultiProperty(property->metaObject()); multiProperty->setName(property->name()); multiProperty->setDisplayName(property->displayName()); multiProperty->setDescription(property->description()); multiProperty->setId(property->id()); addSubProperty(multiProperty); } else { Q_ASSERT(qobject_cast(it->data())); multiProperty = static_cast(it->data()); } multiProperty->addProperty(property->asProperty(), false); } } } } void QtnMultiPropertyDelegate::createSubItemsImpl( QtnDrawContext &context, QList &subItems) { Q_ASSERT(!superDelegates.empty()); superDelegates.at(0)->createSubItems(context, subItems); for (auto &item : subItems) { if (nullptr == item.eventHandler) continue; auto oldEventHandler = item.eventHandler; item.eventHandler = [oldEventHandler, this](QtnEventContext &context, const QtnSubItem &item, QtnPropertyToEdit *toEdit) -> bool // { if (!oldEventHandler(context, item, toEdit)) return false; if (!toEdit->isValid() || toEdit->property() == property() || !property()->isEditableByUser()) { return true; } QtnPropertyToEdit oldToEdit(*toEdit); toEdit->setup(property(), [this, oldToEdit]() -> QWidget * // { QtnMultiPropertyDelegate *thiz = this; auto &p = thiz->owner(); auto propertyToEdit = p.properties.at(0); auto data = new PropertyToEdit; data->owner = &p; data->property = propertyToEdit; p.edited = true; using namespace std::placeholders; data->connections.emplace_back( QObject::connect(propertyToEdit, &QObject::destroyed, std::bind(&QtnMultiPropertyDelegate:: onEditedPropertyDestroyed, data))); auto editor = oldToEdit.createEditor(); if (editor) { data->connections.emplace_back(QObject::connect(editor, &QObject::destroyed, std::bind( &QtnMultiPropertyDelegate::onEditorDestroyed, data))); } else { onEditorDestroyed(data); } return editor; }); return true; }; } } void qtnPropertiesToMultiSet( QtnPropertySet *target, QtnPropertySet *source, bool takeOwnership) { Q_ASSERT(target); Q_ASSERT(source); auto &targetProperties = target->childProperties(); for (auto property : source->childProperties()) { auto it = std::find_if(targetProperties.begin(), targetProperties.end(), [property](const QtnPropertyBase *targetProperty) -> bool { return property->propertyMetaObject() == targetProperty->propertyMetaObject() && property->displayName() == targetProperty->displayName(); }); auto subSet = property->asPropertySet(); if (subSet) { QtnPropertySet *multiSet; if (it == targetProperties.end()) { multiSet = new QtnPropertySet( subSet->childrenOrder(), subSet->compareFunc()); multiSet->setName(subSet->name()); multiSet->setDisplayName(subSet->displayName()); multiSet->setDescription(subSet->description()); multiSet->setId(subSet->id()); multiSet->setState(subSet->stateLocal()); target->addChildProperty(multiSet, true); } else { multiSet = (*it)->asPropertySet(); } qtnPropertiesToMultiSet(multiSet, subSet, takeOwnership); } else { QtnMultiProperty *multiProperty; if (it == targetProperties.end()) { multiProperty = new QtnMultiProperty(property->metaObject()); multiProperty->setName(property->name()); multiProperty->setDisplayName(property->displayName()); multiProperty->setDescription(property->description()); multiProperty->setId(property->id()); target->addChildProperty(multiProperty, true); } else { Q_ASSERT(qobject_cast(*it)); multiProperty = static_cast(*it); } multiProperty->addProperty(property->asProperty(), takeOwnership); } } if (takeOwnership) source->clearChildProperties(); } ================================================ FILE: QtnProperty/MultiProperty.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "Property.h" #include "Delegates/Utils/PropertyDelegateMisc.h" #include #include #include class QtnMultiPropertyDelegate; class QtnConnections; class QTN_IMPORT_EXPORT QtnMultiProperty : public QtnProperty { Q_OBJECT public: explicit QtnMultiProperty( const QMetaObject *propertyMetaObject, QObject *parent = nullptr); virtual ~QtnMultiProperty() override; virtual const QMetaObject *propertyMetaObject() const override; void addProperty(QtnProperty *property, bool own = true); bool hasMultipleValues() const; static QString getMultiValuePlaceholder(); inline const std::vector &getProperties() const; QMetaProperty getMetaProperty() const; private: void onPropertyValueAccept(QtnPropertyValuePtr valueToAccept, bool *accept); void onPropertyWillChange(QtnPropertyChangeReason reason, QtnPropertyValuePtr newValue, int typeId); void onPropertyDidChange(QtnPropertyChangeReason reason); protected: virtual void updatePropertyState() override; virtual void doReset(QtnPropertyChangeReason reason) override; virtual bool loadImpl(QDataStream &stream) override; virtual bool saveImpl(QDataStream &stream) const override; virtual void masterPropertyWillChange( QtnPropertyChangeReason reason) override; virtual void masterPropertyDidChange( QtnPropertyChangeReason reason) override; virtual bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; virtual bool toStrImpl(QString &str) const override; virtual bool fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) override; virtual bool toVariantImpl(QVariant &var) const override; private: void updateStateFrom(QtnProperty *source); void updateMultipleState(bool force); private: std::vector properties; const QMetaObject *mPropertyMetaObject; unsigned m_subPropertyUpdates; bool edited; bool calculateMultipleValues; bool multipleValues; friend class QtnMultiPropertyDelegate; }; const std::vector &QtnMultiProperty::getProperties() const { return properties; } class QtnMultiPropertyDelegate : public QtnPropertyDelegateTypedEx { Q_DISABLE_COPY(QtnMultiPropertyDelegate) typedef QtnPropertyDelegateTypedEx Inherited; public: QtnMultiPropertyDelegate(QtnMultiProperty &owner); virtual ~QtnMultiPropertyDelegate() override; static void Register(QtnPropertyDelegateFactory &factory); private: virtual void init() override; struct PropertyToEdit; static void onEditedPropertyDestroyed(PropertyToEdit *data); static void onEditorDestroyed(PropertyToEdit *data); protected: virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; void createSubItemsImpl( QtnDrawContext &context, QList &subItems) override; private: typedef std::unique_ptr DelegatePtr; std::vector superDelegates; }; QTN_IMPORT_EXPORT void qtnPropertiesToMultiSet( QtnPropertySet *target, QtnPropertySet *source, bool takeOwnership); struct QtnMultiVariant { QVariantList values; }; Q_DECLARE_METATYPE(QtnMultiVariant) ================================================ FILE: QtnProperty/Property.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "Property.h" QtnProperty::QtnProperty(QObject *parent) : QtnPropertyBase(parent) { } QtnProperty::~QtnProperty() { // Do not remove! Will be compile errors. } QtnProperty *QtnProperty::asProperty() { return this; } const QtnProperty *QtnProperty::asProperty() const { return this; } ================================================ FILE: QtnProperty/Property.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_PROPERTY_H #define QTN_PROPERTY_H #include "PropertyBase.h" class QTN_IMPORT_EXPORT QtnProperty : public QtnPropertyBase { Q_OBJECT Q_DISABLE_COPY(QtnProperty) public: virtual ~QtnProperty() override; // casts virtual QtnProperty *asProperty() override; virtual const QtnProperty *asProperty() const override; signals: void propertyValueAccept(QtnPropertyValuePtr valueToAccept, bool *accept); protected: explicit QtnProperty(QObject *parent); }; #endif // QTN_PROPERTY_H ================================================ FILE: QtnProperty/PropertyBase.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyBase.h" #include "PropertySet.h" #include "PropertyConnector.h" #include #include const qint32 QtnPropertyIDInvalid = -1; static quint16 qtnPropertyMagicNumber = 0x1984; const quint8 QtnPropertyBase::STORAGE_VERSION = 2; class QtnPropertyDelegateInfoGetter { Q_DISABLE_COPY(QtnPropertyDelegateInfoGetter) public: virtual QtnPropertyDelegateInfo *delegateInfo() = 0; virtual ~QtnPropertyDelegateInfoGetter() = default; protected: QtnPropertyDelegateInfoGetter() = default; }; class QtnPropertyDelegateInfoGetterValue : public QtnPropertyDelegateInfoGetter { public: QtnPropertyDelegateInfoGetterValue(const QtnPropertyDelegateInfo &delegate); QtnPropertyDelegateInfo *delegateInfo() override; private: QtnPropertyDelegateInfo m_delegateInfo; }; class QtnPropertyDelegateInfoGetterCallback : public QtnPropertyDelegateInfoGetter { public: QtnPropertyDelegateInfoGetterCallback( const QtnPropertyBase::DelegateInfoCallback &callback); QtnPropertyDelegateInfo *delegateInfo() override; private: QtnPropertyBase::DelegateInfoCallback m_callback; QScopedPointer m_delegateInfo; }; static QScriptValue qtnPropertyChangeReasonToScriptValue( QScriptEngine *engine, const QtnPropertyChangeReason &val) { QScriptValue obj(engine, QtnPropertyChangeReason::Int(val)); return obj; } static void qtnPropertyChangeReasonFromScriptValue( const QScriptValue &obj, QtnPropertyChangeReason &val) { val = (QtnPropertyChangeReason::enum_type) obj.toInt32(); } static QScriptValue qtnPropertyValuePtrToScriptValue( QScriptEngine *engine, const QtnPropertyValuePtr &val) { Q_UNUSED(engine); Q_UNUSED(val); // no sutable conversion return QScriptValue(); } static void qtnPropertyValuePtrFromScriptValue( const QScriptValue &obj, QtnPropertyValuePtr &val) { Q_UNUSED(obj); Q_UNUSED(val); // no sutable conversion } typedef const QtnPropertyBase *QtnPropertyBasePtr_t; static QScriptValue qtnPropertyBasePtrToScriptValue( QScriptEngine *engine, const QtnPropertyBasePtr_t &val) { QtnPropertyBasePtr_t value = val; QScriptValue obj = engine->newQObject(const_cast(value)); return obj; } static void qtnPropertyBasePtrFromScriptValue( const QScriptValue &obj, QtnPropertyBasePtr_t &val) { val = qobject_cast(obj.toQObject()); } void qtnScriptRegisterPropertyTypes(QScriptEngine *engine) { qScriptRegisterMetaType(engine, qtnPropertyChangeReasonToScriptValue, qtnPropertyChangeReasonFromScriptValue); qScriptRegisterMetaType(engine, qtnPropertyValuePtrToScriptValue, qtnPropertyValuePtrFromScriptValue); qScriptRegisterMetaType(engine, qtnPropertyBasePtrToScriptValue, qtnPropertyBasePtrFromScriptValue); QScriptValue obj = engine->globalObject(); obj.setProperty("QtnPropertyStateNone", QtnPropertyStateNone, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyStateNonSimple", QtnPropertyStateNonSimple, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyStateInvisible", QtnPropertyStateInvisible, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyStateImmutable", QtnPropertyStateImmutable, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyStateCollapsed", QtnPropertyStateCollapsed, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyStateNonSerialized", QtnPropertyStateNonSerialized, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyChangeReasonNewValue", QtnPropertyChangeReasonNewValue, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyChangeReasonLoadedValue", QtnPropertyChangeReasonLoadedValue, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyChangeReasonValue", QtnPropertyChangeReasonValue, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyChangeReasonName", QtnPropertyChangeReasonName, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyChangeReasonDescription", QtnPropertyChangeReasonDescription, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyChangeReasonId", QtnPropertyChangeReasonId, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyChangeReasonStateLocal", QtnPropertyChangeReasonStateLocal, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyChangeReasonStateInherited", QtnPropertyChangeReasonStateInherited, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyChangeReasonState", QtnPropertyChangeReasonState, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyChangeReasonChildPropertyAdd", QtnPropertyChangeReasonChildPropertyAdd, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyChangeReasonChildPropertyRemove", QtnPropertyChangeReasonChildPropertyRemove, QScriptValue::ReadOnly | QScriptValue::Undeletable); obj.setProperty("QtnPropertyChangeReasonChildren", QtnPropertyChangeReasonChildren, QScriptValue::ReadOnly | QScriptValue::Undeletable); } extern bool qtnPropertyRegister(); QtnPropertyBase::QtnPropertyBase(QObject *parent) : QObject(parent) , mPropertyConnector(nullptr) , m_masterProperty(nullptr) , m_id(QtnPropertyIDInvalid) , m_stateLocal(QtnPropertyStateNone) , m_stateInherited(QtnPropertyStateNone) , changeReasons(0) , timer(0) , updateEvent(nullptr) { static const bool static_reg = qtnPropertyRegister(); Q_UNUSED(static_reg); } bool QtnPropertyBase::event(QEvent *e) { if (e == updateEvent) { updateEvent = nullptr; if (changeReasons != 0) { emit propertyDidChange(QtnPropertyChangeReason(changeReasons)); changeReasons = 0; } return true; } if (e->type() == QEvent::Timer && static_cast(e)->timerId() == timer) { killTimer(timer); timer = 0; if (changeReasons != 0) { emit propertyDidChange(QtnPropertyChangeReason(changeReasons)); changeReasons = 0; } return true; } return QObject::event(e); } QtnPropertyBase::~QtnPropertyBase() { disconnectMasterState(); qtnRemovePropertyAsChild(parent(), this); } const QMetaObject *QtnPropertyBase::propertyMetaObject() const { return metaObject(); } void QtnPropertyBase::setName(const QString &name) { if (objectName() == name) return; QtnPropertyChangeReason reason(QtnPropertyChangeReasonName); if (m_displayName.isEmpty() && !name.isEmpty()) { m_displayName = name; reason |= QtnPropertyChangeReasonDisplayName; } emit propertyWillChange( reason, QtnPropertyValuePtr(&name), qMetaTypeId()); setObjectName(name); emit propertyDidChange(reason); } void QtnPropertyBase::setDisplayName(const QString &displayName) { if (displayName == m_displayName) return; emit propertyWillChange(QtnPropertyChangeReasonDisplayName, QtnPropertyValuePtr(&displayName), qMetaTypeId()); m_displayName = displayName; emit propertyDidChange(QtnPropertyChangeReasonDisplayName); } void QtnPropertyBase::setDescription(const QString &description) { if (m_description == description) return; emit propertyWillChange(QtnPropertyChangeReasonDescription, QtnPropertyValuePtr(&description), qMetaTypeId()); m_description = description; emit propertyDidChange(QtnPropertyChangeReasonDescription); } void QtnPropertyBase::setId(QtnPropertyID id) { if (m_id == id) return; emit propertyWillChange(QtnPropertyChangeReasonId, QtnPropertyValuePtr(&id), qMetaTypeId()); m_id = id; emit propertyDidChange(QtnPropertyChangeReasonId); } bool QtnPropertyBase::isExpanded() const { return (0 == (m_stateLocal & QtnPropertyStateCollapsed)); } void QtnPropertyBase::setState(QtnPropertyState stateToSet, bool force) { setStateInternal(stateToSet, force); } void QtnPropertyBase::updatePropertyState() { auto connector = getConnector(); if (connector) { connector->updatePropertyState(); } } void QtnPropertyBase::setStateInternal( QtnPropertyState stateToSet, bool force, QtnPropertyChangeReason reason) { if (!force && (m_stateLocal == stateToSet)) return; reason |= QtnPropertyChangeReasonStateLocal; reason &= ~QtnPropertyChangeReasonLockToggled; if (m_stateLocal.testFlag(QtnPropertyStateUnlockable) && stateToSet.testFlag(QtnPropertyStateUnlockable)) { if (m_stateLocal.testFlag(QtnPropertyStateImmutable) != stateToSet.testFlag(QtnPropertyStateImmutable)) { reason |= QtnPropertyChangeReasonLockToggled; } } emit propertyWillChange(reason, QtnPropertyValuePtr(&stateToSet), qMetaTypeId()); m_stateLocal = stateToSet; updatePropertyState(); emit propertyDidChange(reason); updateStateInherited(force); } void QtnPropertyBase::addState(QtnPropertyState stateToAdd, bool force) { setState(m_stateLocal | stateToAdd, force); } void QtnPropertyBase::removeState(QtnPropertyState stateToRemove, bool force) { setState(m_stateLocal & ~stateToRemove, force); } void QtnPropertyBase::switchState( QtnPropertyState stateToSwitch, bool switchOn, bool force) { if (switchOn) addState(stateToSwitch, force); else removeState(stateToSwitch, force); } void QtnPropertyBase::toggleState(QtnPropertyState stateToSwitch, bool force) { switchState(stateToSwitch, !(stateLocal() & stateToSwitch), force); } bool QtnPropertyBase::isEditableByUser() const { return !(state() & (QtnPropertyStateImmutable | QtnPropertyStateInvisible)); } bool QtnPropertyBase::isVisible() const { return !(state() & QtnPropertyStateInvisible); } bool QtnPropertyBase::isMultiValue() const { return 0 != (m_stateLocal & QtnPropertyStateMultiValue); } bool QtnPropertyBase::valueIsDefault() const { return 0 == (m_stateLocal & QtnPropertyStateModifiedValue); } bool QtnPropertyBase::isSimple() const { return !m_stateLocal.testFlag(QtnPropertyStateNonSimple); } bool QtnPropertyBase::isLocked() const { return m_stateLocal.testFlag(QtnPropertyStateImmutable); } bool QtnPropertyBase::load(QDataStream &stream) { if (stream.status() != QDataStream::Ok) return false; quint16 magicNumber = 0; stream >> magicNumber; // consistency corrupted if (magicNumber != qtnPropertyMagicNumber) return false; quint8 version = 0; stream >> version; // version incorrect if (version != STORAGE_VERSION) return false; qint32 contentSize = 0; stream >> contentSize; #ifndef QT_NO_DEBUG qint64 posBeforeLoadContent = 0; QIODevice *device = stream.device(); if (device) posBeforeLoadContent = device->pos(); #endif if (!loadImpl(stream)) return false; #ifndef QT_NO_DEBUG qint64 posAfterLoadContent = 0; if (device) posAfterLoadContent = device->pos(); if (posBeforeLoadContent != 0 && posAfterLoadContent != 0 && (qint32(posAfterLoadContent - posBeforeLoadContent) != contentSize)) { Q_ASSERT(false && "contentSize and loadContentImpl inconsistency."); } #endif return stream.status() == QDataStream::Ok; } bool QtnPropertyBase::save(QDataStream &stream) const { if (stream.status() != QDataStream::Ok) return false; // for better consistency stream << qtnPropertyMagicNumber; // for compatibility stream << STORAGE_VERSION; QByteArray data; QDataStream contentStream(&data, QIODevice::WriteOnly); contentStream.setVersion(stream.version()); contentStream.setByteOrder(stream.byteOrder()); contentStream.setFloatingPointPrecision(stream.floatingPointPrecision()); if (!saveImpl(contentStream)) return false; // size of data to save stream << (qint32) data.size(); // save content int savedSize = stream.writeRawData(data.constData(), data.size()); if (savedSize != data.size()) return false; return stream.status() == QDataStream::Ok; } bool QtnPropertyBase::skipLoad(QDataStream &stream) { if (stream.status() != QDataStream::Ok) return false; quint16 magicNumber = 0; stream >> magicNumber; // consistency corrupted if (magicNumber != qtnPropertyMagicNumber) return false; quint8 version = 0; stream >> version; // version incorrect if (version != STORAGE_VERSION) return false; qint32 contentSize = 0; stream >> contentSize; { int read = stream.skipRawData(contentSize); // corrupted data if (read != contentSize) return false; } return stream.status() == QDataStream::Ok; } bool QtnPropertyBase::loadImpl(QDataStream &stream) { Q_ASSERT(stream.status() == QDataStream::Ok); qint16 version = 0; stream >> version; // incorrect version if (version != STORAGE_VERSION) return false; QtnPropertyState::Int stateLocal = QtnPropertyStateNone; QtnPropertyState::Int stateInherited = QtnPropertyStateNone; stream >> stateLocal; stream >> stateInherited; m_stateLocal = QtnPropertyState(stateLocal); m_stateInherited = QtnPropertyState(stateInherited); return stream.status() == QDataStream::Ok; } bool QtnPropertyBase::saveImpl(QDataStream &stream) const { Q_ASSERT(stream.status() == QDataStream::Ok); qint16 version = STORAGE_VERSION; stream << version; stream << (QtnPropertyState::Int) m_stateLocal; stream << (QtnPropertyState::Int) m_stateInherited; return stream.status() == QDataStream::Ok; } bool QtnPropertyBase::fromStrImpl(const QString &, QtnPropertyChangeReason) { return false; } bool QtnPropertyBase::toStrImpl(QString &str) const { Q_UNUSED(str); return false; } bool QtnPropertyBase::fromStr( const QString &str, QtnPropertyChangeReason reason) { if (!isWritable()) return false; QString trimmedStr = str.trimmed(); return fromStrImpl(trimmedStr, reason); } bool QtnPropertyBase::toStr(QString &str) const { return toStrImpl(str); } bool QtnPropertyBase::fromVariant( const QVariant &var, QtnPropertyChangeReason reason) { if (!isWritable()) return false; return fromVariantImpl(var, reason); } bool QtnPropertyBase::toVariant(QVariant &var) const { return toVariantImpl(var); } QtnProperty *QtnPropertyBase::asProperty() { return nullptr; } const QtnProperty *QtnPropertyBase::asProperty() const { return nullptr; } QtnPropertySet *QtnPropertyBase::asPropertySet() { return nullptr; } const QtnPropertySet *QtnPropertyBase::asPropertySet() const { return nullptr; } QtnPropertyBase *QtnPropertyBase::getRootProperty() { auto result = this; do { auto mp = result->getMasterProperty(); if (nullptr == mp) break; result = mp; } while (true); return result; } QtnPropertySet *QtnPropertyBase::getRootPropertySet() { auto p = this; while (p != nullptr) { auto set = p->asPropertySet(); auto mp = p->getRootProperty(); if (set && mp == p && qobject_cast(set->parent()) == nullptr) { return set; } if (mp != p) { p = mp; } else { p = qobject_cast(p->parent()); } } return nullptr; } bool QtnPropertyBase::fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) { if (var.canConvert()) return fromStr(var.value(), reason); else return false; } bool QtnPropertyBase::toVariantImpl(QVariant &var) const { QString str; if (!toStr(str)) return false; var.setValue(str); return true; } void QtnPropertyBase::updateStateInherited(bool force) { Q_UNUSED(force); /* does nothing by default */ } void QtnPropertyBase::connectMasterState(QtnPropertyBase *masterProperty) { Q_ASSERT(nullptr != masterProperty); disconnectMasterState(); m_masterProperty = masterProperty; beforeUpdateStateFromMasterProperty(); doUpdateStateFromMasterProperty(); QObject::connect(masterProperty, &QObject::destroyed, this, &QtnPropertyBase::onMasterPropertyDestroyed); QObject::connect(masterProperty, &QtnPropertyBase::propertyWillChange, this, &QtnPropertyBase::masterPropertyWillChange); QObject::connect(masterProperty, &QtnPropertyBase::propertyDidChange, this, &QtnPropertyBase::masterPropertyDidChange); } void QtnPropertyBase::disconnectMasterState() { if (nullptr != m_masterProperty) { QObject::disconnect(m_masterProperty, &QObject::destroyed, this, &QtnPropertyBase::onMasterPropertyDestroyed); QObject::disconnect(m_masterProperty, &QtnPropertyBase::propertyWillChange, this, &QtnPropertyBase::masterPropertyWillChange); QObject::disconnect(m_masterProperty, &QtnPropertyBase::propertyDidChange, this, &QtnPropertyBase::masterPropertyDidChange); m_masterProperty = nullptr; } } void QtnPropertyBase::postUpdateEvent( QtnPropertyChangeReason reason, int afterMS) { changeReasons |= reason; if (afterMS > 0) { if (timer == 0) { timer = startTimer(afterMS); } } else if (nullptr == updateEvent) { updateEvent = new QEvent(QEvent::User); QCoreApplication::postEvent(this, updateEvent); } } void QtnPropertyBase::setStateInherited(QtnPropertyState stateToSet, bool force) { if (!force && (m_stateInherited == stateToSet)) return; emit propertyWillChange(QtnPropertyChangeReasonStateInherited, QtnPropertyValuePtr(&stateToSet), qMetaTypeId()); m_stateInherited = stateToSet; emit propertyDidChange(QtnPropertyChangeReasonStateInherited); updateStateInherited(force); } QtnPropertyState QtnPropertyBase::masterPropertyState() const { return !(stateLocal() & QtnPropertyStateIgnoreDirectParentState) ? m_masterProperty->state() : m_masterProperty->stateInherited(); } void QtnPropertyBase::masterPropertyWillChange(QtnPropertyChangeReason reason) { if (reason & QtnPropertyChangeReasonState) { Q_ASSERT(sender() == m_masterProperty); beforeUpdateStateFromMasterProperty(); } } void QtnPropertyBase::masterPropertyDidChange(QtnPropertyChangeReason reason) { if (reason & QtnPropertyChangeReasonState) { Q_ASSERT(sender() == m_masterProperty); doUpdateStateFromMasterProperty(); } } void QtnPropertyBase::beforeUpdateStateFromMasterProperty() { auto newState = masterPropertyState(); if (m_stateInherited == newState) return; emit propertyWillChange(QtnPropertyChangeReasonStateInherited, QtnPropertyValuePtr(&newState), qMetaTypeId()); } void QtnPropertyBase::doUpdateStateFromMasterProperty() { auto newState = masterPropertyState(); if (m_stateInherited == newState) return; m_stateInherited = newState; emit propertyDidChange(QtnPropertyChangeReasonStateInherited); updateStateInherited(false); } QVariant QtnPropertyBase::valueAsVariant() const { QVariant result; toVariant(result); return result; } void QtnPropertyBase::onMasterPropertyDestroyed(QObject *object) { Q_ASSERT(object == m_masterProperty); Q_UNUSED(object); m_masterProperty = nullptr; } QDataStream &operator<<(QDataStream &stream, const QtnPropertyBase &property) { property.save(stream); return stream; } QDataStream &operator>>(QDataStream &stream, QtnPropertyBase &property) { property.load(stream); return stream; } void QtnPropertyBase::setExpanded(bool expanded) { if (expanded) expand(); else collapse(); } bool QtnPropertyBase::isResettable() const { return isWritable() && 0 != (stateLocal() & QtnPropertyStateResettable); } void QtnPropertyBase::reset(QtnPropertyChangeReason reason) { if (!isResettable()) return; reason |= QtnPropertyChangeReasonResetValue; doReset(reason); } void QtnPropertyBase::doReset(QtnPropertyChangeReason reason) { auto connector = getConnector(); if (connector) { connector->resetPropertyValue(reason); } } bool QtnPropertyBase::isWritable() const { return (0 == (state() & QtnPropertyStateImmutable)); } bool QtnPropertyBase::isUnlockable() const { return !m_stateInherited.testFlag(QtnPropertyStateImmutable) && m_stateLocal.testFlag(QtnPropertyStateUnlockable); } void QtnPropertyBase::setLocked(bool locked, QtnPropertyChangeReason reason) { Q_ASSERT(m_stateLocal & QtnPropertyStateUnlockable); auto state = m_stateLocal; state.setFlag(QtnPropertyStateImmutable, locked); setStateInternal(state, false, reason); } void QtnPropertyBase::toggleLock(QtnPropertyChangeReason reason) { setLocked(!isLocked(), reason); } bool QtnPropertyBase::isCollapsed() const { return (0 != (m_stateLocal & QtnPropertyStateCollapsed)); } void QtnPropertyBase::setCollapsed(bool collapsed) { if (collapsed) collapse(); else expand(); } QtnPropertyState QtnPropertyBase::state() const { return m_stateLocal | m_stateInherited; } const QtnPropertyDelegateInfo *QtnPropertyBase::delegateInfo() const { if (m_delegateInfoGetter.isNull()) return 0; return m_delegateInfoGetter->delegateInfo(); } void QtnPropertyBase::setDelegateInfo(const QtnPropertyDelegateInfo &delegate) { m_delegateInfoGetter.reset( new QtnPropertyDelegateInfoGetterValue(delegate)); } void QtnPropertyBase::setDelegateInfoCallback( const DelegateInfoCallback &callback) { m_delegateInfoGetter.reset((callback != nullptr) ? new QtnPropertyDelegateInfoGetterCallback(callback) : nullptr); } void QtnPropertyBase::setDelegateAttribute( const QByteArray &attributeName, const QVariant &attributeValue) { if (m_delegateInfoGetter.isNull()) { setDelegateInfo(QtnPropertyDelegateInfo()); } Q_ASSERT(!m_delegateInfoGetter.isNull()); auto delegate = m_delegateInfoGetter->delegateInfo(); Q_ASSERT(delegate); delegate->attributes[attributeName] = attributeValue; } QtnPropertyDelegateInfoGetterValue::QtnPropertyDelegateInfoGetterValue( const QtnPropertyDelegateInfo &delegate) : m_delegateInfo(delegate) { } QtnPropertyDelegateInfo *QtnPropertyDelegateInfoGetterValue::delegateInfo() { return &m_delegateInfo; } QtnPropertyDelegateInfoGetterCallback::QtnPropertyDelegateInfoGetterCallback( const QtnPropertyBase::DelegateInfoCallback &callback) : m_callback(callback) { Q_ASSERT(callback != nullptr); } QtnPropertyDelegateInfo *QtnPropertyDelegateInfoGetterCallback::delegateInfo() { if (m_delegateInfo.isNull()) { m_delegateInfo.reset(new QtnPropertyDelegateInfo(m_callback())); } return m_delegateInfo.data(); } ================================================ FILE: QtnProperty/PropertyBase.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_PROPERTY_BASE_H #define QTN_PROPERTY_BASE_H #include "Auxiliary/PropertyAux.h" #include "Auxiliary/PropertyDelegateInfo.h" #include #include #include class QScriptEngine; class QtnPropertySet; class QtnProperty; class QtnPropertyConnector; class QtnPropertyDelegateInfoGetter; class QTN_IMPORT_EXPORT QtnPropertyBase : public QObject { Q_OBJECT Q_DISABLE_COPY(QtnPropertyBase) Q_PROPERTY(QString name READ name) Q_PROPERTY(QString displayName READ displayName) Q_PROPERTY(QString description READ description) Q_PROPERTY(qint32 id READ id) Q_PROPERTY(bool isEditable READ isWritable) Q_PROPERTY(bool isEditableByUser READ isEditableByUser) Q_PROPERTY(quint32 state READ state) Q_PROPERTY(QVariant value READ valueAsVariant WRITE fromVariant) friend class QtnPropertyConnector; friend class QtnPropertySet; inline void setConnector(QtnPropertyConnector *connector); public: static const quint8 STORAGE_VERSION; using DelegateInfoCallback = std::function; virtual ~QtnPropertyBase() override; virtual const QMetaObject *propertyMetaObject() const; inline QString name() const; void setName(const QString &name); inline QString displayName() const; void setDisplayName(const QString &displayName); inline QString description() const; void setDescription(const QString &description); inline QtnPropertyID id() const; void setId(QtnPropertyID id); bool isExpanded() const; void setExpanded(bool expanded); bool isCollapsed() const; void setCollapsed(bool collapsed); bool isResettable() const; void reset(QtnPropertyChangeReason reason = QtnPropertyChangeReason()); bool isWritable() const; bool isUnlockable() const; inline void expand(); inline void collapse(); inline QtnPropertyConnector *getConnector() const; inline bool isQObjectProperty() const; void setLocked(bool locked, QtnPropertyChangeReason reason = QtnPropertyChangeReason()); void toggleLock(QtnPropertyChangeReason reason = QtnPropertyChangeReason()); // states QtnPropertyState state() const; inline QtnPropertyState stateLocal() const; inline QtnPropertyState stateInherited() const; void setState(QtnPropertyState stateToSet, bool force = false); void addState(QtnPropertyState stateToAdd, bool force = false); void removeState(QtnPropertyState stateToRemove, bool force = false); void switchState( QtnPropertyState stateToSwitch, bool switchOn, bool force = false); void toggleState(QtnPropertyState stateToSwitch, bool force = false); bool isEditableByUser() const; bool isVisible() const; bool isMultiValue() const; bool valueIsDefault() const; bool isSimple() const; bool isLocked() const; // serialization bool load(QDataStream &stream); bool save(QDataStream &stream) const; static bool skipLoad(QDataStream &stream); // string conversion bool fromStr(const QString &str, QtnPropertyChangeReason reason = QtnPropertyChangeReasonNewValue); bool toStr(QString &str) const; // variant conversion bool fromVariant(const QVariant &var, QtnPropertyChangeReason reason = QtnPropertyChangeReasonNewValue); bool toVariant(QVariant &var) const; // casts virtual QtnProperty *asProperty(); virtual const QtnProperty *asProperty() const; virtual QtnPropertySet *asPropertySet(); virtual const QtnPropertySet *asPropertySet() const; inline QtnPropertyBase *getMasterProperty() const; QtnPropertyBase *getRootProperty(); QtnPropertySet *getRootPropertySet(); void connectMasterState(QtnPropertyBase *masterProperty); void disconnectMasterState(); void postUpdateEvent(QtnPropertyChangeReason reason, int afterMS = 0); // getter/setter for "value" property QVariant valueAsVariant() const; // delegates const QtnPropertyDelegateInfo *delegateInfo() const; void setDelegateInfo(const QtnPropertyDelegateInfo &delegateInfo); void setDelegateInfoCallback(const DelegateInfoCallback &callback); void setDelegateAttribute( const QByteArray &attributeName, const QVariant &attributeValue); Q_SIGNALS: void propertyWillChange(QtnPropertyChangeReason reason, QtnPropertyValuePtr newValue, int typeId); void propertyDidChange(QtnPropertyChangeReason reason); protected: QtnPropertyBase(QObject *parent); virtual void doReset(QtnPropertyChangeReason reason); virtual bool event(QEvent *e) override; // serialization implementation virtual bool loadImpl(QDataStream &stream); virtual bool saveImpl(QDataStream &stream) const; // string conversion implementation virtual bool fromStrImpl(const QString &, QtnPropertyChangeReason reason); virtual bool toStrImpl(QString &str) const; // variant conversion implementation virtual bool fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason); virtual bool toVariantImpl(QVariant &var) const; // inherited states support virtual void updateStateInherited(bool force); void setStateInherited(QtnPropertyState stateToSet, bool force = false); void setStateInternal(QtnPropertyState stateToSet, bool force = false, QtnPropertyChangeReason reason = QtnPropertyChangeReason()); virtual void masterPropertyWillChange(QtnPropertyChangeReason reason); virtual void masterPropertyDidChange(QtnPropertyChangeReason reason); virtual void updatePropertyState(); private: QtnPropertyState masterPropertyState() const; void onMasterPropertyDestroyed(QObject *object); void beforeUpdateStateFromMasterProperty(); void doUpdateStateFromMasterProperty(); private: QtnPropertyConnector *mPropertyConnector; QtnPropertyBase *m_masterProperty; QString m_displayName; QString m_description; QtnPropertyID m_id; QtnPropertyState m_stateLocal; QtnPropertyState m_stateInherited; int changeReasons; int timer; QEvent *updateEvent; QScopedPointer m_delegateInfoGetter; }; QString QtnPropertyBase::name() const { return objectName(); } QString QtnPropertyBase::displayName() const { return m_displayName; } QString QtnPropertyBase::description() const { return m_description; } QtnPropertyID QtnPropertyBase::id() const { return m_id; } void QtnPropertyBase::expand() { removeState(QtnPropertyStateCollapsed); } void QtnPropertyBase::collapse() { addState(QtnPropertyStateCollapsed); } void QtnPropertyBase::setConnector(QtnPropertyConnector *connector) { mPropertyConnector = connector; } QtnPropertyConnector *QtnPropertyBase::getConnector() const { return mPropertyConnector; } bool QtnPropertyBase::isQObjectProperty() const { return (nullptr != getConnector()); } QtnPropertyState QtnPropertyBase::stateLocal() const { return m_stateLocal; } QtnPropertyState QtnPropertyBase::stateInherited() const { return m_stateInherited; } QtnPropertyBase *QtnPropertyBase::getMasterProperty() const { return m_masterProperty; } QTN_IMPORT_EXPORT QDataStream &operator<<( QDataStream &stream, const QtnPropertyBase &property); QTN_IMPORT_EXPORT QDataStream &operator>>( QDataStream &stream, QtnPropertyBase &property); QTN_IMPORT_EXPORT void qtnScriptRegisterPropertyTypes(QScriptEngine *engine); Q_DECLARE_METATYPE(const QtnPropertyBase *) Q_DECLARE_METATYPE(QtnPropertyBase *) #endif // QTN_PROPERTY_BASE_H ================================================ FILE: QtnProperty/PropertyConnector.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyConnector.h" #include "PropertyBase.h" #include "Property.h" #include "QObjectPropertySet.h" #include "IQtnPropertyStateProvider.h" QtnPropertyConnector::QtnPropertyConnector(QtnPropertyBase *property) : QObject(property) , property(property) , object(nullptr) , ignoreStateChangeCounter(0) { Q_ASSERT(nullptr != property); Q_ASSERT(nullptr == property->getConnector()); property->setConnector(this); } void QtnPropertyConnector::connectProperty( QObject *object, const QMetaProperty &metaProperty) { this->object = object; this->metaProperty = metaProperty; auto metaObject = this->metaObject(); if (metaProperty.hasNotifySignal()) { auto slot = metaObject->method(metaObject->indexOfSlot("onValueChanged()")); QObject::connect(object, metaProperty.notifySignal(), this, slot); } auto stateProvider = dynamic_cast(object); if (nullptr != stateProvider) { auto srcMetaObject = object->metaObject(); auto signal = srcMetaObject->method( srcMetaObject->indexOfSignal("modifiedSetChanged()")); if (signal.isValid()) { auto slot = metaObject->method( metaObject->indexOfSlot("onModifiedSetChanged()")); QObject::connect(object, signal, this, slot); } signal = srcMetaObject->method(srcMetaObject->indexOfSignal( "propertyStateChanged(QMetaProperty)")); if (signal.isValid()) { auto slot = metaObject->method(metaObject->indexOfSlot( "onPropertyStateChanged(QMetaProperty)")); QObject::connect(object, signal, this, slot); } } else { property->switchState( QtnPropertyStateResettable, metaProperty.isResettable()); } } void QtnPropertyConnector::updatePropertyState() { if (!property || !object || !metaProperty.isValid()) { return; } auto stateProvider = dynamic_cast(object); if (!stateProvider) { return; } ignoreStateChangeCounter++; stateProvider->setPropertyState(metaProperty, property->stateLocal()); ignoreStateChangeCounter--; } bool QtnPropertyConnector::isResettablePropertyValue() const { return metaProperty.isResettable(); } void QtnPropertyConnector::resetPropertyValue(QtnPropertyChangeReason reason) { if (nullptr != object && nullptr != property && metaProperty.isResettable()) { if (property->isResettable()) { reason |= QtnPropertyChangeReasonResetValue; emit property->propertyWillChange(reason, nullptr, 0); metaProperty.reset(object); emit property->propertyDidChange(reason); } } } void QtnPropertyConnector::onValueChanged() { if (nullptr != property) { property->postUpdateEvent(QtnPropertyChangeReasonNewValue, 20); } } void QtnPropertyConnector::onPropertyStateChanged( const QMetaProperty &metaProperty) { if (ignoreStateChangeCounter == 0 && nullptr != property && metaProperty.propertyIndex() == this->metaProperty.propertyIndex()) { onModifiedSetChanged(); } } void QtnPropertyConnector::onModifiedSetChanged() { if (nullptr != property) { auto stateProvider = dynamic_cast(object); if (nullptr == stateProvider) return; QtnPropertyState state; state = stateProvider->getPropertyState(metaProperty); state |= qtnPropertyStateToAdd(metaProperty); state.setFlag(QtnPropertyStateCollapsed, property->isCollapsed()); state.setFlag(QtnPropertyStateResettable, metaProperty.isResettable()); property->setState(state); } } ================================================ FILE: QtnProperty/PropertyConnector.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "Config.h" #include "Auxiliary/PropertyAux.h" #include #include class QtnPropertyBase; class QtnPropertySet; class QTN_IMPORT_EXPORT QtnPropertyConnector : public QObject { Q_OBJECT public: explicit QtnPropertyConnector(QtnPropertyBase *property); void connectProperty(QObject *object, const QMetaProperty &metaProperty); void updatePropertyState(); bool isResettablePropertyValue() const; void resetPropertyValue(QtnPropertyChangeReason reason); inline QObject *getObject() const; inline const QMetaProperty &getMetaProperty() const; private slots: void onValueChanged(); void onModifiedSetChanged(); void onPropertyStateChanged(const QMetaProperty &metaProperty); private: QtnPropertyBase *property; QObject *object; QMetaProperty metaProperty; unsigned ignoreStateChangeCounter; }; QObject *QtnPropertyConnector::getObject() const { return object; } const QMetaProperty &QtnPropertyConnector::getMetaProperty() const { return metaProperty; } ================================================ FILE: QtnProperty/PropertyCore.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYCORE_H #define PROPERTYCORE_H #include "PropertySet.h" #include "Core/PropertyBool.h" #include "Core/PropertyInt.h" #include "Core/PropertyUInt.h" #include "Core/PropertyFloat.h" #include "Core/PropertyDouble.h" #include "Core/PropertyEnum.h" #include "Core/PropertyEnumFlags.h" #include "Core/PropertyQString.h" #include "Core/PropertyQRect.h" #include "Core/PropertyQRectF.h" #include "Core/PropertyQPoint.h" #include "Core/PropertyQPointF.h" #include "Core/PropertyQSize.h" #include "Core/PropertyQSizeF.h" #endif // PROPERTYCORE_H ================================================ FILE: QtnProperty/PropertyDelegateAttrs.h ================================================ /******************************************************************************* Copyright 2017-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License")(); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "Config.h" #include QTN_IMPORT_EXPORT QByteArray qtnPrecisionAttr(); QTN_IMPORT_EXPORT QByteArray qtnMinAttr(); QTN_IMPORT_EXPORT QByteArray qtnMaxAttr(); QTN_IMPORT_EXPORT QByteArray qtnStepAttr(); QTN_IMPORT_EXPORT QByteArray qtnMultiplierAttr(); QTN_IMPORT_EXPORT QByteArray qtnMultiLineEditAttr(); QTN_IMPORT_EXPORT QByteArray qtnMaxLengthAttr(); QTN_IMPORT_EXPORT QByteArray qtnPlaceholderAttr(); QTN_IMPORT_EXPORT QByteArray qtnItemsAttr(); QTN_IMPORT_EXPORT QByteArray qtnEditableAttr(); QTN_IMPORT_EXPORT QByteArray qtnInvalidColorAttr(); QTN_IMPORT_EXPORT QByteArray qtnShowRelativePathAttr(); QTN_IMPORT_EXPORT QByteArray qtnFileModeAttr(); QTN_IMPORT_EXPORT QByteArray qtnFileNameFilterAttr(); QTN_IMPORT_EXPORT QByteArray qtnFileNameFiltersAttr(); QTN_IMPORT_EXPORT QByteArray qtnDefaultDirAttr(); QTN_IMPORT_EXPORT QByteArray qtnOptionsAttr(); QTN_IMPORT_EXPORT QByteArray qtnViewModeAttr(); QTN_IMPORT_EXPORT QByteArray qtnAcceptModeAttr(); QTN_IMPORT_EXPORT QByteArray qtnDefaultSuffixAttr(); QTN_IMPORT_EXPORT QByteArray qtnSuffixAttr(); QTN_IMPORT_EXPORT QByteArray qtnGetCandidatesFnAttr(); QTN_IMPORT_EXPORT QByteArray qtnCreateCandidateFnAttr(); QTN_IMPORT_EXPORT QByteArray qtnCreateCandidateIconAttr(); QTN_IMPORT_EXPORT QByteArray qtnCreateCandidateToolTipAttr(); QTN_IMPORT_EXPORT QByteArray qtnLabelFalseAttr(); QTN_IMPORT_EXPORT QByteArray qtnLabelTrueAttr(); QTN_IMPORT_EXPORT QByteArray qtnShapeAttr(); QTN_IMPORT_EXPORT QByteArray qtnRgbSubItemsAttr(); QTN_IMPORT_EXPORT QByteArray qtnFillColorAttr(); QTN_IMPORT_EXPORT QByteArray qtnLiveUpdateAttr(); QTN_IMPORT_EXPORT QByteArray qtnDrawBorderAttr(); QTN_IMPORT_EXPORT QByteArray qtnUpdateByScrollAttr(); QTN_IMPORT_EXPORT QByteArray qtnAnimateAttr(); QTN_IMPORT_EXPORT QByteArray qtnToolTipAttr(); QTN_IMPORT_EXPORT QByteArray qtnXDisplayNameAttr(); QTN_IMPORT_EXPORT QByteArray qtnXDescriptionAttr(); QTN_IMPORT_EXPORT QByteArray qtnYDisplayNameAttr(); QTN_IMPORT_EXPORT QByteArray qtnYDescriptionAttr(); QTN_IMPORT_EXPORT QByteArray qtnZDisplayNameAttr(); QTN_IMPORT_EXPORT QByteArray qtnZDescriptionAttr(); QTN_IMPORT_EXPORT QByteArray qtnLeftDisplayNameAttr(); QTN_IMPORT_EXPORT QByteArray qtnLeftDescriptionAttr(); QTN_IMPORT_EXPORT QByteArray qtnTopDisplayNameAttr(); QTN_IMPORT_EXPORT QByteArray qtnTopDescriptionAttr(); QTN_IMPORT_EXPORT QByteArray qtnRightDisplayNameAttr(); QTN_IMPORT_EXPORT QByteArray qtnRightDescriptionAttr(); QTN_IMPORT_EXPORT QByteArray qtnBottomDisplayNameAttr(); QTN_IMPORT_EXPORT QByteArray qtnBottomDescriptionAttr(); QTN_IMPORT_EXPORT QByteArray qtnWidthDisplayNameAttr(); QTN_IMPORT_EXPORT QByteArray qtnWidthDescriptionAttr(); QTN_IMPORT_EXPORT QByteArray qtnHeightDisplayNameAttr(); QTN_IMPORT_EXPORT QByteArray qtnHeightDescriptionAttr(); QTN_IMPORT_EXPORT QByteArray qtnCoordinateModeAttr(); QTN_IMPORT_EXPORT QByteArray qtnFieldDelegateNameAttr(); QTN_IMPORT_EXPORT QByteArray qtnLineEditDelegate(); QTN_IMPORT_EXPORT QByteArray qtnSelectFileDelegate(); QTN_IMPORT_EXPORT QByteArray qtnSelectFontDelegate(); QTN_IMPORT_EXPORT QByteArray qtnSelectColorDelegateName(); QTN_IMPORT_EXPORT QByteArray qtnCallbackDelegate(); QTN_IMPORT_EXPORT QByteArray qtnComboBoxDelegate(); QTN_IMPORT_EXPORT QByteArray qtnCheckBoxDelegate(); QTN_IMPORT_EXPORT QByteArray qtnLTWHDelegateName(); QTN_IMPORT_EXPORT QByteArray qtnLTRBDelegateName(); QTN_IMPORT_EXPORT QByteArray qtnGeoCoordDelegateName(); QTN_IMPORT_EXPORT QByteArray qtnGeoPointDelegateName(); QTN_IMPORT_EXPORT QByteArray qtnSliderBoxDelegate(); QTN_IMPORT_EXPORT QByteArray qtnSpinBoxDelegate(); QTN_IMPORT_EXPORT QByteArray qtnSolidDelegateName(); QTN_IMPORT_EXPORT QByteArray qtnLinkDelegateName(); QTN_IMPORT_EXPORT QByteArray qtnShowAllAttr(); QTN_IMPORT_EXPORT QByteArray qtnShowNoPenAttr(); QTN_IMPORT_EXPORT QByteArray qtnEditColorAttr(); QTN_IMPORT_EXPORT QByteArray qtnEditStyleAttr(); QTN_IMPORT_EXPORT QByteArray qtnEditCapStyleAttr(); QTN_IMPORT_EXPORT QByteArray qtnEditJoinStyleAttr(); QTN_IMPORT_EXPORT QByteArray qtnEditWidthAttr(); QTN_IMPORT_EXPORT QByteArray qtnTitleAttr(); QTN_IMPORT_EXPORT QByteArray qtnTranslateAttribute(); struct QtnPropertyDelegateInfo; QTN_IMPORT_EXPORT void qtnInitPercentSpinBoxDelegate( QtnPropertyDelegateInfo &delegate); QTN_IMPORT_EXPORT void qtnInitDegreeSpinBoxDelegate( QtnPropertyDelegateInfo &delegate); QTN_IMPORT_EXPORT double qtnHundredPercent(double value); template inline T qtnDefaultGet(T value) { return value; } ================================================ FILE: QtnProperty/PropertyDelegateMetaEnum.cpp ================================================ /******************************************************************************* Copyright 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyDelegateMetaEnum.h" #include "Delegates/Utils/PropertyEditorHandler.h" #include "Delegates/PropertyDelegateFactory.h" #include "Property.h" #include "PropertyDelegateAttrs.h" #include "QtnProperty/Delegates/Utils/PropertyEditorAux.h" #include #include #include class QtnPropertyDelegateMetaEnum::EditorHandler : public QtnPropertyEditorHandlerBase { QtnPropertyDelegateMetaEnum *mOwner; public: EditorHandler(QtnPropertyDelegateMetaEnum *delegate, QComboBox &editor); QComboBox &comboBox() const; protected: virtual void updateEditor() override; void updateValue(int value); private: void onCurrentIndexChanged(int index); unsigned updating; }; QtnPropertyDelegateMetaEnum::QtnPropertyDelegateMetaEnum( const QMetaEnum &metaEnum, QtnPropertyBase *property, bool translate) : QtnPropertyDelegateWithValueEditor(*property) , mMetaEnum(metaEnum) , mShouldTranslate(translate) { } void QtnPropertyDelegateMetaEnum::Register( QMetaEnum metaEnum, QtnPropertyDelegateFactory *factory, bool translate) { if (!factory) factory = &QtnPropertyDelegateFactory::staticInstance(); factory->registerDelegate(&QtnProperty::staticMetaObject, [metaEnum, translate](QtnPropertyBase &owner) -> QtnPropertyDelegate * { return new QtnPropertyDelegateMetaEnum(metaEnum, &owner, translate); }, delegateName(metaEnum)); } QtnPropertyDelegateInfo QtnPropertyDelegateMetaEnum::delegateInfo( const QMetaEnum &metaEnum) { QtnPropertyDelegateInfo result; result.name = delegateName(metaEnum); return result; } QByteArray QtnPropertyDelegateMetaEnum::delegateName(const QMetaEnum &metaEnum) { const char *cscope = metaEnum.scope(); const char *cname = metaEnum.name(); auto scope = QByteArray::fromRawData(cscope, qstrlen(cscope)); auto name = QByteArray::fromRawData(cname, qstrlen(cname)); return scope + "." + name; } int QtnPropertyDelegateMetaEnum::currentValue() const { QVariant v; propertyImmutable()->toVariant(v); return int(v.toLongLong()); } bool QtnPropertyDelegateMetaEnum::propertyValueToStrImpl( QString &strValue) const { strValue = valueToStr(currentValue()); return !strValue.isNull(); } QString QtnPropertyDelegateMetaEnum::valueToStr(int value) const { auto key = mMetaEnum.valueToKey(value); if (!key) return QString(); return keyToStr(key); } QString QtnPropertyDelegateMetaEnum::keyToStr(const char *key) const { return mShouldTranslate ? QCoreApplication::translate(mMetaEnum.scope(), key, mMetaEnum.name()) : QString(QLatin1String(key)); } QByteArray qtnTranslateAttribute() { return QByteArrayLiteral("translate"); } QWidget *QtnPropertyDelegateMetaEnum::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { QComboBox *combo = new QtnPropertyComboBox(this, parent); for (int i = 0, count = mMetaEnum.keyCount(); i < count; i++) { combo->addItem( keyToStr(mMetaEnum.key(i)), QVariant(mMetaEnum.value(i))); } combo->setGeometry(rect); new EditorHandler(this, *combo); if (inplaceInfo && stateProperty()->isEditableByUser()) combo->showPopup(); return combo; } void QtnPropertyDelegateMetaEnum::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnTranslateAttribute(), mShouldTranslate); } QtnPropertyDelegateMetaEnum::EditorHandler::EditorHandler( QtnPropertyDelegateMetaEnum *delegate, QComboBox &editor) : QtnPropertyEditorHandlerBase(delegate, editor) , mOwner(delegate) , updating(0) { updateEditor(); QObject::connect(&editor, static_cast(&QComboBox::currentIndexChanged), this, &EditorHandler::onCurrentIndexChanged); } QComboBox &QtnPropertyDelegateMetaEnum::EditorHandler::comboBox() const { return *static_cast(editorBase()); } void QtnPropertyDelegateMetaEnum::EditorHandler::updateEditor() { ++updating; if (stateProperty()->isMultiValue()) comboBox().setCurrentIndex(-1); else { int index = comboBox().findData(mOwner->currentValue()); if (index >= 0) comboBox().setCurrentIndex(index); } --updating; } void QtnPropertyDelegateMetaEnum::EditorHandler::updateValue(int value) { if (updating > 0) return; if (propertyBase()) propertyBase()->fromVariant(value, delegate()->editReason()); } void QtnPropertyDelegateMetaEnum::EditorHandler::onCurrentIndexChanged( int index) { if (index < 0) return; QVariant data = comboBox().itemData(index); if (data.canConvert()) updateValue(data.toInt()); } ================================================ FILE: QtnProperty/PropertyDelegateMetaEnum.h ================================================ /******************************************************************************* Copyright (c) 2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "QtnProperty/Delegates/Utils/PropertyDelegateMisc.h" #include class QtnPropertyDelegateFactory; class QTN_IMPORT_EXPORT QtnPropertyDelegateMetaEnum : public QtnPropertyDelegateWithValueEditor { Q_DISABLE_COPY(QtnPropertyDelegateMetaEnum) QMetaEnum mMetaEnum; bool mShouldTranslate; class EditorHandler; public: explicit QtnPropertyDelegateMetaEnum(const QMetaEnum &metaEnum, QtnPropertyBase *property, bool translate = false); static void Register(QMetaEnum metaEnum, QtnPropertyDelegateFactory *factory, bool translate = false); template static void Register( QtnPropertyDelegateFactory *factory, bool translate = false) { Register(QMetaEnum::fromType(), factory, translate); } static QtnPropertyDelegateInfo delegateInfo(const QMetaEnum &metaEnum); template static inline QtnPropertyDelegateInfo delegateInfo() { return delegateInfo(QMetaEnum::fromType()); } static QByteArray delegateName(const QMetaEnum &metaEnum); template static inline QByteArray delegateName() { return delegateName(QMetaEnum::fromType()); } int currentValue() const; virtual bool propertyValueToStrImpl(QString &strValue) const override; QString valueToStr(int value) const; QString keyToStr(const char *key) const; protected: virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; }; ================================================ FILE: QtnProperty/PropertyGUI.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef PROPERTYGUI_H #define PROPERTYGUI_H #include "PropertySet.h" #include "GUI/PropertyQColor.h" #include "GUI/PropertyQFont.h" #include "GUI/PropertyQPen.h" #include "GUI/PropertyQBrush.h" #include "GUI/PropertyQVector3D.h" #include "GUI/PropertyButton.h" #endif // PROPERTYGUI_H ================================================ FILE: QtnProperty/PropertyInt64.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyInt64.h" #include "QObjectPropertySet.h" #include "Delegates/PropertyDelegateFactory.h" #include "Delegates/Utils/PropertyEditorAux.h" #include "Delegates/Utils/PropertyEditorHandler.h" #include "Delegates/Utils/PropertyDelegateSliderBox.h" #include "Utils/QtnInt64SpinBox.h" #include "MultiProperty.h" #include "PropertyDelegateAttrs.h" #include #include class QtnPropertyInt64SpinBoxHandler : public QtnPropertyEditorHandlerVT { public: QtnPropertyInt64SpinBoxHandler( QtnPropertyDelegateInt64 *delegate, QtnInt64SpinBox &editor); private: virtual void updateEditor() override; private: QtnPropertyDelegateInt64 *m_delegate; }; QtnPropertyInt64Base::QtnPropertyInt64Base(QObject *parent) : QtnNumericPropertyBase>(parent) { } bool QtnPropertyInt64Base::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { bool ok = false; ValueType value = str.toLongLong(&ok); if (!ok) return false; return setValue(value, reason); } bool QtnPropertyInt64Base::toStrImpl(QString &str) const { str = QString::number(value()); return true; } bool QtnPropertyInt64Base::fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) { bool ok = false; ValueType value = var.toLongLong(&ok); if (!ok) return false; return setValue(value, reason); } QtnPropertyInt64::QtnPropertyInt64(QObject *parent) : QtnNumericPropertyValue(parent) { } void QtnPropertyDelegateInt64::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyInt64Base::staticMetaObject, &qtnCreateDelegate, qtnSpinBoxDelegate()); factory.registerDelegate(&QtnPropertyInt64Base::staticMetaObject, &qtnCreateDelegate< QtnPropertyDelegateSlideBoxTyped, QtnPropertyInt64Base>, qtnSliderBoxDelegate()); } qint64 QtnPropertyDelegateInt64::stepValue() const { return m_step.isValid() ? m_step.toLongLong() : owner().stepValue(); } qint64 QtnPropertyDelegateInt64::minValue() const { return m_min.isValid() ? m_min.toLongLong() : owner().minValue(); } qint64 QtnPropertyDelegateInt64::maxValue() const { return m_max.isValid() ? m_max.toLongLong() : owner().maxValue(); } qint64 QtnPropertyDelegateInt64::currentValue() const { return qBound(minValue(), owner().value(), maxValue()); } QtnPropertyDelegateInt64::QtnPropertyDelegateInt64(QtnPropertyInt64Base &owner) : QtnPropertyDelegateTyped(owner) { } bool QtnPropertyDelegateInt64::acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const { if (QtnPropertyDelegateTyped< QtnPropertyInt64Base>::acceptKeyPressedForInplaceEditImpl(keyEvent)) return true; return qtnAcceptForNumEdit(keyEvent, NUM_SIGNED_INT); } QWidget *QtnPropertyDelegateInt64::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { auto spinBox = new QtnInt64SpinBox(parent); spinBox->setSuffix(m_suffix); spinBox->setGeometry(rect); new QtnPropertyInt64SpinBoxHandler(this, *spinBox); spinBox->selectAll(); if (stateProperty()->isEditableByUser()) qtnInitNumEdit(spinBox, inplaceInfo, NUM_SIGNED_INT); return spinBox; } void QtnPropertyDelegateInt64::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnSuffixAttr(), m_suffix); m_min = info.attributes.value(qtnMinAttr()); m_max = info.attributes.value(qtnMaxAttr()); m_step = info.attributes.value(qtnStepAttr()); if (m_step.isValid()) { bool ok; qint64 step = m_step.toLongLong(&ok); if (!ok) { m_step = QVariant(); } else { m_step = step; } } fixMinMaxVariant(m_min, m_max); } bool QtnPropertyDelegateInt64::propertyValueToStrImpl(QString &strValue) const { strValue = QLocale().toString(currentValue()); strValue.append(m_suffix); return true; } QtnPropertyInt64Callback::QtnPropertyInt64Callback(QObject *parent) : QtnSinglePropertyCallback(parent) { } QtnPropertyInt64SpinBoxHandler::QtnPropertyInt64SpinBoxHandler( QtnPropertyDelegateInt64 *delegate, QtnInt64SpinBox &editor) : QtnPropertyEditorHandlerVT(delegate, editor) , m_delegate(delegate) { updateEditor(); editor.setKeyboardTracking(false); editor.installEventFilter(this); QObject::connect(&editor, static_cast( &QtnInt64SpinBox::valueChanged), this, &QtnPropertyInt64SpinBoxHandler::onValueChanged); } void QtnPropertyInt64SpinBoxHandler::updateEditor() { updating++; editor().setReadOnly(!stateProperty()->isEditableByUser()); editor().setSingleStep(m_delegate->stepValue()); editor().setRange(m_delegate->minValue(), m_delegate->maxValue()); if (stateProperty()->isMultiValue()) { editor().setValue(editor().minimum()); editor().setSpecialValueText( QtnMultiProperty::getMultiValuePlaceholder()); } else { editor().setValue(m_delegate->currentValue()); editor().setSpecialValueText(QString()); } editor().selectAll(); updating--; } ================================================ FILE: QtnProperty/PropertyInt64.h ================================================ /******************************************************************************* Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "Auxiliary/PropertyTemplates.h" #include "Delegates/Utils/PropertyDelegateMisc.h" class QTN_IMPORT_EXPORT QtnPropertyInt64Base : public QtnNumericPropertyBase> { Q_OBJECT private: QtnPropertyInt64Base(const QtnPropertyInt64Base &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyInt64Base(QObject *parent); protected: // string conversion implementation virtual bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; virtual bool toStrImpl(QString &str) const override; // variant conversion implementation virtual bool fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyInt64Base) }; class QTN_IMPORT_EXPORT QtnPropertyInt64 : public QtnNumericPropertyValue { Q_OBJECT private: QtnPropertyInt64(const QtnPropertyInt64 &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyInt64(QObject *parent); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyInt64, QtnPropertyInt64Base) }; P_PROPERTY_DECL_ALL_OPERATORS(QtnPropertyInt64Base, qint64) class QTN_IMPORT_EXPORT QtnPropertyInt64Callback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyInt64Callback( const QtnPropertyInt64Callback &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyInt64Callback(QObject *parent); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyInt64Callback, QtnPropertyInt64Base) }; class QTN_IMPORT_EXPORT QtnPropertyDelegateInt64 : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateInt64) QString m_suffix; QVariant m_min; QVariant m_max; QVariant m_step; public: QtnPropertyDelegateInt64(QtnPropertyInt64Base &owner); static void Register(QtnPropertyDelegateFactory &factory); qint64 stepValue() const; qint64 minValue() const; qint64 maxValue() const; qint64 currentValue() const; protected: virtual bool acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; ================================================ FILE: QtnProperty/PropertyQKeySequence.cpp ================================================ /******************************************************************************* Copyright (c) 2017-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQKeySequence.h" #include "Delegates/PropertyDelegateFactory.h" #include "Delegates/Utils/PropertyEditorAux.h" #include "Delegates/Utils/PropertyEditorHandler.h" #include "Core/PropertyQString.h" #include "MultiProperty.h" #include #include class QtnPropertyQKeySequenceEditHandler : public QtnPropertyEditorHandler { public: QtnPropertyQKeySequenceEditHandler( QtnPropertyDelegate *delegate, QKeySequenceEdit &editor); protected: virtual void updateEditor() override; void updateValue(const QKeySequence &seq); }; QtnPropertyQKeySequenceBase::QtnPropertyQKeySequenceBase(QObject *parent) : QtnSinglePropertyBase(parent) { } bool QtnPropertyQKeySequenceBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { return setValue( QKeySequence::fromString(str, QKeySequence::PortableText), reason); } bool QtnPropertyQKeySequenceBase::toStrImpl(QString &str) const { str = value().toString(QKeySequence::PortableText); return true; } bool QtnPropertyQKeySequenceBase::fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) { QKeySequence keySequence; switch (var.type()) { case QVariant::String: return fromStrImpl(var.toString(), reason); case QVariant::KeySequence: keySequence = var.value(); break; default: break; } return setValue(keySequence, reason); } bool QtnPropertyQKeySequenceBase::toVariantImpl(QVariant &var) const { var.setValue(value()); return var.isValid(); } QtnPropertyQKeySequenceCallback::QtnPropertyQKeySequenceCallback( QObject *parent) : QtnSinglePropertyCallback(parent) { } QtnPropertyQKeySequence::QtnPropertyQKeySequence(QObject *parent) : QtnSinglePropertyValue(parent) { } QtnPropertyDelegateQKeySequence::QtnPropertyDelegateQKeySequence( QtnPropertyQKeySequenceBase &owner) : QtnPropertyDelegateTyped(owner) { } void QtnPropertyDelegateQKeySequence::Register( QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault( &QtnPropertyQKeySequenceBase::staticMetaObject, &qtnCreateDelegate, "QKeySequence"); } QWidget *QtnPropertyDelegateQKeySequence::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *) { if (!stateProperty()->isEditableByUser()) { auto lineEdit = new QLineEdit(parent); lineEdit->setGeometry(rect); lineEdit->setReadOnly(true); auto text = owner().value().toString(QKeySequence::NativeText); lineEdit->setText(text); lineEdit->setPlaceholderText( QtnPropertyQString::getEmptyPlaceholderStr()); lineEdit->selectAll(); return lineEdit; } auto editor = new QKeySequenceEdit(parent); editor->setGeometry(rect); new QtnPropertyQKeySequenceEditHandler(this, *editor); return editor; } bool QtnPropertyDelegateQKeySequence::propertyValueToStrImpl( QString &strValue) const { strValue = owner().value().toString(QKeySequence::NativeText); if (strValue.isEmpty()) strValue = QtnPropertyQString::getEmptyPlaceholderStr(); return true; } QtnPropertyQKeySequenceEditHandler::QtnPropertyQKeySequenceEditHandler( QtnPropertyDelegate *delegate, QKeySequenceEdit &editor) : QtnPropertyEditorHandler(delegate, editor) { updateEditor(); QObject::connect(&editor, &QKeySequenceEdit::keySequenceChanged, this, &QtnPropertyQKeySequenceEditHandler::updateValue); } void QtnPropertyQKeySequenceEditHandler::updateEditor() { if (stateProperty()->isMultiValue()) { editor().clear(); } else { editor().setKeySequence(property().value()); } } void QtnPropertyQKeySequenceEditHandler::updateValue(const QKeySequence &seq) { if (propertyBase()) property().setValue(seq, delegate()->editReason()); } ================================================ FILE: QtnProperty/PropertyQKeySequence.h ================================================ /******************************************************************************* Copyright (c) 2017-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "Auxiliary/PropertyTemplates.h" #include "Delegates/Utils/PropertyDelegateMisc.h" #include class QTN_IMPORT_EXPORT QtnPropertyQKeySequenceBase : public QtnSinglePropertyBase { Q_OBJECT QtnPropertyQKeySequenceBase( const QtnPropertyQKeySequenceBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQKeySequenceBase(QObject *parent); protected: virtual bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; virtual bool toStrImpl(QString &str) const override; virtual bool fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) override; virtual bool toVariantImpl(QVariant &var) const override; }; class QTN_IMPORT_EXPORT QtnPropertyQKeySequenceCallback : public QtnSinglePropertyCallback { Q_OBJECT QtnPropertyQKeySequenceCallback( const QtnPropertyQKeySequenceCallback &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQKeySequenceCallback(QObject *parent = nullptr); }; class QTN_IMPORT_EXPORT QtnPropertyQKeySequence : public QtnSinglePropertyValue { Q_OBJECT QtnPropertyQKeySequence( const QtnPropertyQKeySequence &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQKeySequence(QObject *parent = nullptr); }; class QTN_IMPORT_EXPORT QtnPropertyDelegateQKeySequence : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateQKeySequence) public: typedef QtnPropertyDelegateTyped Inherited; QtnPropertyDelegateQKeySequence(QtnPropertyQKeySequenceBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; }; ================================================ FILE: QtnProperty/PropertyQVariant.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyQVariant.h" #include "QObjectPropertySet.h" #include "Delegates/PropertyDelegateFactory.h" #include "Delegates/Utils/PropertyEditorAux.h" #include "Delegates/Utils/PropertyEditorHandler.h" #include "MultiProperty.h" #include "Core/PropertyQString.h" #include "CustomPropertyEditorDialog.h" #include #include bool qtnCompareQVariants(const QVariant &left, const QVariant &right) { if (left.userType() != right.userType()) { return false; } switch (left.type()) { case QVariant::Hash: { const auto leftMap = left.toHash(); const auto rightMap = right.toHash(); if (leftMap.size() != rightMap.size()) { return false; } auto leftIt = leftMap.cbegin(); for (; leftIt != leftMap.cend(); ++leftIt) { auto rightIt = rightMap.find(leftIt.key()); if (rightIt == rightMap.end()) { return false; } if (!qtnCompareQVariants(leftIt.value(), rightIt.value())) { return false; } } return true; } case QVariant::Map: { const auto leftMap = left.toMap(); const auto rightMap = right.toMap(); if (leftMap.size() != rightMap.size()) { return false; } auto leftIt = leftMap.cbegin(); auto rightIt = rightMap.cbegin(); for (; leftIt != leftMap.cend(); ++leftIt, ++rightIt) { if (leftIt.key() != rightIt.key()) { return false; } if (!qtnCompareQVariants(leftIt.value(), rightIt.value())) { return false; } } return true; } case QVariant::List: { const auto leftList = left.toList(); const auto rightList = left.toList(); int count = leftList.size(); if (count != rightList.size()) { return false; } for (int i = 0; i < count; i++) { if (!qtnCompareQVariants(leftList.at(i), rightList.at(i))) { return false; } } return true; } default: break; } return left == right; } class QtnPropertyQVariantEditBttnHandler : public QtnPropertyEditorBttnHandler { public: QtnPropertyQVariantEditBttnHandler( QtnPropertyDelegate *delegate, QtnLineEditBttn &editor); protected: virtual void revertInput() override; virtual void onToolButtonClick() override; virtual void updateEditor() override; private: void onEditingFinished(); void onToolButtonClicked(bool); void onApplyData(const QVariant &data); CustomPropertyEditorDialog *dialog; DialogContainerPtr dialogContainer; bool is_object; }; QtnPropertyQVariantBase::QtnPropertyQVariantBase(QObject *parent) : QtnSinglePropertyBase(parent) { } bool QtnPropertyQVariantBase::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { return setValue(str, reason); } bool QtnPropertyQVariantBase::toStrImpl(QString &str) const { str = value().toString(); return true; } bool QtnPropertyQVariantBase::fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) { return setValue(var, reason); } bool QtnPropertyQVariantBase::toVariantImpl(QVariant &var) const { var = value(); return var.isValid(); } QtnPropertyQVariantCallback::QtnPropertyQVariantCallback( QObject *object, const QMetaProperty &metaProperty, QObject *parent) : QtnSinglePropertyCallback(parent) { setCallbackValueGet([object, metaProperty]() -> QVariant { return metaProperty.read(object); }); setCallbackValueSet([object, metaProperty](QVariant value, QtnPropertyChangeReason /*reason*/) { metaProperty.write(object, value); }); setCallbackValueEqual([object, metaProperty](QVariant value) -> bool { auto thisValue = metaProperty.read(object); return qtnCompareQVariants(thisValue, value); }); } QtnPropertyQVariantCallback::QtnPropertyQVariantCallback(QObject *parent) : QtnSinglePropertyCallback(parent) { } QtnPropertyQVariant::QtnPropertyQVariant(QObject *parent) : QtnSinglePropertyValue(parent) { } QString QtnPropertyQVariant::valueToString(const QVariant &value) { return !variantIsObject(value.type()) ? value.toString() : QString(); } bool QtnPropertyQVariant::variantIsObject(QVariant::Type type) { switch (type) { case QVariant::Hash: case QVariant::Map: case QVariant::StringList: case QVariant::List: return true; default: break; } return false; } QString QtnPropertyQVariant::getPlaceholderStr(QVariant::Type type) { switch (type) { case QVariant::Hash: case QVariant::Map: return tr("(Dictionary)"); case QVariant::StringList: case QVariant::List: return tr("(List)"); default: break; } return QtnPropertyQString::getEmptyPlaceholderStr(); } QtnPropertyDelegateQVariant::QtnPropertyDelegateQVariant( QtnPropertyQVariantBase &owner) : QtnPropertyDelegateTyped(owner) { } void QtnPropertyDelegateQVariant::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyQVariantBase::staticMetaObject, &qtnCreateDelegate, "QVariant"); } bool QtnPropertyDelegateQVariant::acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const { if (QtnPropertyDelegateTyped:: acceptKeyPressedForInplaceEditImpl(keyEvent)) return true; // accept any printable key return qtnAcceptForLineEdit(keyEvent); } QWidget *QtnPropertyDelegateQVariant::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { auto editor = new QtnLineEditBttn(parent); editor->setGeometry(rect); new QtnPropertyQVariantEditBttnHandler(this, *editor); qtnInitLineEdit(editor->lineEdit, inplaceInfo); return editor; } bool QtnPropertyDelegateQVariant::propertyValueToStrImpl( QString &strValue) const { auto value = owner().value(); strValue = QtnPropertyQVariant::valueToString(value); if (strValue.isEmpty()) strValue = QtnPropertyQVariant::getPlaceholderStr(value.type()); return true; } bool QtnPropertyDelegateQVariant::isPlaceholderColor() const { return QtnPropertyQVariant::valueToString(owner().value()).isEmpty(); } QtnPropertyQVariantEditBttnHandler::QtnPropertyQVariantEditBttnHandler( QtnPropertyDelegate *delegate, QtnLineEditBttn &editor) : QtnPropertyEditorHandlerType(delegate, editor) , dialog(new CustomPropertyEditorDialog(&editor)) , is_object(false) { dialogContainer = connectDialog(dialog); updateEditor(); editor.lineEdit->installEventFilter(this); QObject::connect(editor.toolButton, &QToolButton::clicked, this, &QtnPropertyQVariantEditBttnHandler::onToolButtonClicked); QObject::connect(editor.lineEdit, &QLineEdit::editingFinished, this, &QtnPropertyQVariantEditBttnHandler::onEditingFinished); QObject::connect(dialog, &CustomPropertyEditorDialog::apply, this, &QtnPropertyQVariantEditBttnHandler::onApplyData); } void QtnPropertyQVariantEditBttnHandler::revertInput() { reverted = true; } void QtnPropertyQVariantEditBttnHandler::onToolButtonClick() { onToolButtonClicked(false); } void QtnPropertyQVariantEditBttnHandler::updateEditor() { auto edit = editor().lineEdit; edit->setReadOnly(!stateProperty()->isEditableByUser()); if (stateProperty()->isMultiValue()) { edit->clear(); edit->setPlaceholderText(QtnMultiProperty::getMultiValuePlaceholder()); } else { QVariant value; value = property().value(); if (QtnPropertyQVariant::variantIsObject(value.type())) { is_object = true; edit->setText(QString()); } else { is_object = false; edit->setText(value.toString()); } edit->setPlaceholderText( QtnPropertyQVariant::getPlaceholderStr(value.type())); edit->selectAll(); } } void QtnPropertyQVariantEditBttnHandler::onEditingFinished() { if (canApply()) { auto text = editor().lineEdit->text(); if (!is_object || !text.isEmpty()) { if (is_object || text != property().value().toString()) property().setValue(text, delegate()->editReason()); updateEditor(); } } applyReset(); } void QtnPropertyQVariantEditBttnHandler::onToolButtonClicked(bool) { QVariant data; auto text = editor().lineEdit->text(); auto property = &this->property(); auto value = property->value(); if (!is_object && text != value.toString()) { data = text; } else data = value; auto dialogContainer = this->dialogContainer; reverted = true; dialog->setReadOnly(!stateProperty()->isEditableByUser()); volatile bool destroyed = false; auto connection = QObject::connect(this, &QObject::destroyed, [&destroyed]() mutable { destroyed = true; }); if (dialog->execute(property->name(), data) && !destroyed) property->setValue(data, delegate()->editReason()); if (!destroyed) { QObject::disconnect(connection); updateEditor(); } Q_UNUSED(dialogContainer); } void QtnPropertyQVariantEditBttnHandler::onApplyData(const QVariant &data) { property().setValue(data, delegate()->editReason()); updateEditor(); } ================================================ FILE: QtnProperty/PropertyQVariant.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "Auxiliary/PropertyTemplates.h" #include "Delegates/Utils/PropertyDelegateMisc.h" #include class QTN_IMPORT_EXPORT QtnPropertyQVariantBase : public QtnSinglePropertyBase { Q_OBJECT private: QtnPropertyQVariantBase( const QtnPropertyQVariantBase &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQVariantBase(QObject *parent); protected: virtual bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; virtual bool toStrImpl(QString &str) const override; virtual bool fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) override; virtual bool toVariantImpl(QVariant &var) const override; }; class QTN_IMPORT_EXPORT QtnPropertyQVariantCallback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyQVariantCallback( const QtnPropertyQVariantCallback &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQVariantCallback(QObject *object, const QMetaProperty &metaProperty, QObject *parent = nullptr); explicit QtnPropertyQVariantCallback(QObject *parent = nullptr); }; class QTN_IMPORT_EXPORT QtnPropertyQVariant : public QtnSinglePropertyValue { Q_OBJECT private: QtnPropertyQVariant(const QtnPropertyQVariant &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyQVariant(QObject *parent); static QString valueToString(const QVariant &value); static bool variantIsObject(QVariant::Type type); static QString getPlaceholderStr(QVariant::Type type); }; class QTN_IMPORT_EXPORT QtnPropertyDelegateQVariant : public QtnPropertyDelegateTyped { Q_DISABLE_COPY(QtnPropertyDelegateQVariant) public: typedef QtnPropertyDelegateTyped Inherited; QtnPropertyDelegateQVariant(QtnPropertyQVariantBase &owner); static void Register(QtnPropertyDelegateFactory &factory); protected: virtual bool acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; virtual bool isPlaceholderColor() const override; }; QTN_IMPORT_EXPORT bool qtnCompareQVariants( const QVariant &left, const QVariant &right); ================================================ FILE: QtnProperty/PropertySet.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertySet.h" #include #include #include void qtnAddPropertyAsChild( QObject *parent, QtnPropertyBase *child, bool moveOwnership) { QtnPropertySet *propertySet = qobject_cast(parent); if (propertySet) propertySet->addChildProperty(child, moveOwnership); } void qtnRemovePropertyAsChild(QObject *parent, QtnPropertyBase *child) { QtnPropertySet *propertySet = qobject_cast(parent); if (propertySet) propertySet->removeChildProperty(child); } QtnPropertySet::QtnPropertySet(QObject *parent) : QtnPropertyBase(parent) , m_childrenOrder(NoSort) { } QtnPropertySet::QtnPropertySet( SortOrder childrenOrder, const CompareFunc &compareFunc) : QtnPropertyBase(nullptr) , m_compareFunc(compareFunc) , m_childrenOrder(childrenOrder) { } QtnPropertySet::~QtnPropertySet() { clearChildProperties(); } int QtnPropertySet::compareByName( const QtnPropertyBase *a, const QtnPropertyBase *b) { return QString::localeAwareCompare(a->name(), b->name()); } QList QtnPropertySet::findChildProperties( QString name, Qt::FindChildOptions options) { QList result; // normilize name name = name.trimmed(); // if name is dot separated property path if (name.contains('.')) { QString nameHead = name.section('.', 0, 0); if (nameHead.isEmpty()) return result; QString nameTail = name.section('.', 1); if (nameTail.isEmpty()) return result; QList headResult = findChildProperties(nameHead, options); for (auto headProperty : headResult) { QtnPropertySet *headPropertySet = headProperty->asPropertySet(); if (!headPropertySet) continue; result.append( headPropertySet->findChildProperties(nameTail, options)); } } else { for (auto childProperty : m_childProperties) { if (childProperty->name() == name) result.append(childProperty); } if (options & Qt::FindChildrenRecursively) { for (auto childProperty : m_childProperties) { QtnPropertySet *propertySet = childProperty->asPropertySet(); if (propertySet) propertySet->findChildPropertiesRecursive(name, result); } } } return result; } QList QtnPropertySet::findChildProperties( const QRegularExpression &re, Qt::FindChildOptions options) { QList result; for (auto childProperty : m_childProperties) { if (re.match(childProperty->name()).isValid()) result.append(childProperty); } if (options & Qt::FindChildrenRecursively) { for (auto childProperty : m_childProperties) { QtnPropertySet *propertySet = childProperty->asPropertySet(); if (propertySet) propertySet->findChildPropertiesRecursive(re, result); } } return result; } QtnPropertyBase *QtnPropertySet::findChildProperty(QtnPropertyID id) { for (auto childProperty : m_childProperties) { if (childProperty->id() == id) return childProperty; } return nullptr; } void QtnPropertySet::clearChildProperties() { if (m_childProperties.isEmpty()) return; emit propertyWillChange( QtnPropertyChangeReasonChildPropertyRemove, nullptr, 0); // Original list is cleared to avoid interference with property destructors, // where properties are removed from the parent's list. auto childProperties = std::move(m_childProperties); for (auto p : childProperties) { if (p->parent() == this) delete p; } emit propertyDidChange(QtnPropertyChangeReasonChildPropertyRemove); } bool QtnPropertySet::addChildProperty( QtnPropertyBase *childProperty, bool moveOwnership, int index) { Q_CHECK_PTR(childProperty); emit propertyWillChange(QtnPropertyChangeReasonChildPropertyAdd, QtnPropertyValuePtr(childProperty), qMetaTypeId()); switch (m_childrenOrder) { case NoSort: break; case Ascend: case Descend: index = 0; for (int i = m_childProperties.size() - 1; i >= 0; --i) { auto p = m_childProperties.at(i); int compare = m_compareFunc(childProperty, p); if (compare == 0 || (m_childrenOrder == Ascend && compare > 0) || (m_childrenOrder == Descend && compare < 0)) { index = i + 1; break; } } break; } if (index < 0) m_childProperties.append(childProperty); else m_childProperties.insert(index, childProperty); if (moveOwnership) childProperty->setParent(this); emit propertyDidChange(QtnPropertyChangeReasonChildPropertyAdd); childProperty->setStateInherited(state()); return true; } bool QtnPropertySet::removeChildProperty(QtnPropertyBase *childProperty) { Q_CHECK_PTR(childProperty); int childPropertyIndex = m_childProperties.indexOf(childProperty); if (childPropertyIndex < 0) return false; emit propertyWillChange(QtnPropertyChangeReasonChildPropertyRemove, QtnPropertyValuePtr(childProperty), qMetaTypeId()); m_childProperties.erase(m_childProperties.begin() + childPropertyIndex); if (childProperty->parent() == this) childProperty->setParent(nullptr); emit propertyDidChange(QtnPropertyChangeReasonChildPropertyRemove); return true; } QtnPropertySet *QtnPropertySet::createNew(QObject *parentForNew) const { return createNewImpl(parentForNew); } QtnPropertySet *QtnPropertySet::createCopy(QObject *parentForCopy) const { return createCopyImpl(parentForCopy); } bool QtnPropertySet::copyValues( QtnPropertySet *propertySetCopyFrom, QtnPropertyState ignoreMask) { return copyValuesImpl(propertySetCopyFrom, ignoreMask); } QtnPropertySet *QtnPropertySet::asPropertySet() { return this; } const QtnPropertySet *QtnPropertySet::asPropertySet() const { return this; } void QtnPropertySet::doReset(QtnPropertyChangeReason reason) { Q_ASSERT(reason & QtnPropertyChangeReasonResetValue); for (auto &p : childProperties()) { p->reset(reason); } } void QtnPropertySet::updateStateInherited(bool force) { for (auto childProperty : m_childProperties) { childProperty->setStateInherited(state(), force); } } QtnPropertySet *QtnPropertySet::createNewImpl(QObject *parentForNew) const { Q_UNUSED(parentForNew); return nullptr; } QtnPropertySet *QtnPropertySet::createCopyImpl(QObject *parentForCopy) const { Q_UNUSED(parentForCopy); return nullptr; } bool QtnPropertySet::copyValuesImpl( QtnPropertySet *propertySetCopyFrom, QtnPropertyState ignoreMask) { Q_UNUSED(propertySetCopyFrom); Q_UNUSED(ignoreMask); return false; } bool QtnPropertySet::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { static QRegExp parserLine(QStringLiteral("^\\s*([^=]+)=(.*)$")); QStringList lines = str.split(QChar::LineFeed, QString::SkipEmptyParts); if (lines.isEmpty()) return true; bool ok = true; for (const auto &line : lines) { if (!parserLine.exactMatch(line)) { qDebug() << "Cannot parse string: " << line; ok = false; continue; } QStringList params = parserLine.capturedTexts(); if (params.size() != 3) { qDebug() << "Cannot parse string: " << line; ok = false; continue; } QString propertyPath = params[1]; QString propertyStrValue = params[2]; QList subProperties = findChildProperties(propertyPath, Qt::FindChildrenRecursively); if (subProperties.size() != 1) { qDebug() << "Ambiguous property path: " << propertyPath; ok = false; continue; } if (subProperties[0]->state() & QtnPropertyStateNonSerialized) continue; propertyStrValue = propertyStrValue.trimmed(); if (propertyStrValue.startsWith('"') && propertyStrValue.endsWith('"')) { propertyStrValue = propertyStrValue.mid(1, propertyStrValue.length() - 2); } if (!subProperties[0]->fromStr(propertyStrValue, reason)) { qDebug() << QString( "Cannot convert property %1<%2> from string \"%3\"") .arg(subProperties[0]->name(), subProperties[0]->metaObject()->className(), propertyStrValue); ok = false; continue; } } return ok; } bool QtnPropertySet::fromJson( const QJsonObject &jsonObject, QtnPropertyChangeReason reason) { bool ok = true; for (auto it = jsonObject.begin(), end = jsonObject.end(); it != end; ++it) { if (it.value().type() != QJsonValue::Object) { qDebug() << "Json object expected"; ok = false; continue; } QString cppName = it.key(); auto childProperties = findChildProperties(cppName, Qt::FindDirectChildrenOnly); if (childProperties.isEmpty()) { qDebug() << "Cannot find property " << cppName; ok = false; continue; } else if (childProperties.size() > 1) { qDebug() << "Ambiguous property " << cppName; ok = false; continue; } if (childProperties[0]->state() & QtnPropertyStateNonSerialized) continue; auto childPropertySet = childProperties[0]->asPropertySet(); if (childPropertySet) { if (!childPropertySet->fromJson(it.value().toObject(), reason)) { qDebug() << "Cannot load \"" << childPropertySet->name() << "\" from JSON"; ok = false; } } else { auto childProperty = childProperties[0]->asProperty(); if (childProperty) { auto jsonProperty = it.value().toObject(); if (!jsonProperty.contains("value")) { qDebug() << "Cannot parse \"value\" attribute"; ok = false; continue; } QString propertyValue = jsonProperty.value("value").toString(); if (!childProperty->fromStr(propertyValue, reason)) { qDebug() << "Cannot convert value" << propertyValue << "to property" << childProperty->name(); ok = false; } } else { Q_ASSERT(false && "Cannot recognize property type"); ok = false; } } } return ok; } bool QtnPropertySet::toJson(QJsonObject &jsonObject) const { bool ok = true; for (auto childPropertyBase : childProperties()) { if (childPropertyBase->state() & QtnPropertyStateNonSerialized) continue; QJsonObject jsonSubObject; auto childPropertySet = childPropertyBase->asPropertySet(); if (childPropertySet) { if (!childPropertySet->toJson(jsonSubObject)) { qDebug() << "Cannot save \"" << childPropertySet->name() << "\" to JSON"; ok = false; continue; } } else { auto childProperty = childPropertyBase->asProperty(); if (childProperty) { QString value; if (!childProperty->toStr(value)) { qDebug() << "Cannot convert property \"" << childProperty->name() << "\" to QString"; ok = false; continue; } jsonSubObject.insert("value", value); } else { Q_ASSERT(false && "Cannot recognize property type"); ok = false; continue; } } jsonObject.insert(childPropertyBase->name(), jsonSubObject); } return ok; } bool QtnPropertySet::toStrImpl(QString &str) const { return toStrWithPrefix(str, QString()); } bool QtnPropertySet::fromVariantImpl( const QVariant &v, QtnPropertyChangeReason reason) { if (!v.isValid() || v.type() == QVariant::Map) { return fromJson(QJsonObject::fromVariantMap(v.toMap()), reason); } return false; } bool QtnPropertySet::toVariantImpl(QVariant &v) const { QJsonObject json; bool ok = toJson(json); if (ok) v = json.toVariantMap(); return ok; } bool QtnPropertySet::loadImpl(QDataStream &stream) { if (!QtnPropertyBase::loadImpl(stream)) return false; if (stream.status() != QDataStream::Ok) return false; quint8 version = 0; stream >> version; // version incorrect if (version != STORAGE_VERSION) return false; forever { QtnPropertyID id = QtnPropertyIDInvalid; stream >> id; // no child properties any more if (id == QtnPropertyIDInvalid) break; QtnPropertyBase *childProperty = findChildProperty(id); if (!childProperty) { // cannot find subproperty -> skip if (!skipLoad(stream)) return false; continue; } if (childProperty->state() & QtnPropertyStateNonSerialized) { // should not load such subproperty if (!skipLoad(stream)) return false; continue; } if (!childProperty->load(stream)) return false; } return stream.status() == QDataStream::Ok; } bool QtnPropertySet::saveImpl(QDataStream &stream) const { if (!QtnPropertyBase::saveImpl(stream)) return false; if (stream.status() != QDataStream::Ok) return false; // for compatibility stream << STORAGE_VERSION; for (auto childProperty : m_childProperties) { if (childProperty->state() & QtnPropertyStateNonSerialized) continue; if (childProperty->id() == QtnPropertyIDInvalid) { // serializable properties should have unique ids Q_ASSERT(false && "serializable properties should have unique ids"); continue; } // save child property id stream << childProperty->id(); // save child property if (!childProperty->save(stream)) return false; } // mark end of children list stream << QtnPropertyIDInvalid; return stream.status() == QDataStream::Ok; } void QtnPropertySet::findChildPropertiesRecursive( const QString &name, QList &result) { for (auto childProperty : m_childProperties) { if (childProperty->name() == name) result.append(childProperty); QtnPropertySet *propertySet = childProperty->asPropertySet(); if (propertySet) propertySet->findChildPropertiesRecursive(name, result); } } void QtnPropertySet::findChildPropertiesRecursive( const QRegularExpression &re, QList &result) { for (auto childProperty : m_childProperties) { if (re.match(childProperty->name()).isValid()) result.append(childProperty); QtnPropertySet *propertySet = childProperty->asPropertySet(); if (propertySet) propertySet->findChildPropertiesRecursive(re, result); } } bool QtnPropertySet::toStrWithPrefix(QString &str, const QString &prefix) const { for (auto childPropertyBase : m_childProperties) { if (childPropertyBase->state() & QtnPropertyStateNonSerialized) continue; QtnProperty *childProperty = childPropertyBase->asProperty(); if (childProperty) { QString strValue; if (!childProperty->toStr(strValue)) return false; str.append(QStringLiteral("%1%2 = %3\n") .arg(prefix, childProperty->name(), strValue)); } else { auto childPropertySet = childPropertyBase->asPropertySet(); if (childPropertySet) { if (!childPropertySet->toStrWithPrefix(str, QStringLiteral("%1%2.").arg( prefix, childPropertySet->name()))) return false; } else { // neither property no propertyset Q_UNREACHABLE(); } } } return true; } ================================================ FILE: QtnProperty/PropertySet.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_PROPERTY_SET_H #define QTN_PROPERTY_SET_H #include "Property.h" class QJsonObject; class QTN_IMPORT_EXPORT QtnPropertySet : public QtnPropertyBase { Q_OBJECT Q_DISABLE_COPY(QtnPropertySet) public: enum SortOrder { NoSort, Ascend, Descend, }; static int compareByName( const QtnPropertyBase *a, const QtnPropertyBase *b); using CompareFunc = std::function; explicit QtnPropertySet(QObject *parent = nullptr); explicit QtnPropertySet(SortOrder childrenOrder, const CompareFunc &compareFunc = compareByName); virtual ~QtnPropertySet() override; inline SortOrder childrenOrder() const; inline const CompareFunc &compareFunc() const; public slots: // sub properties inline bool hasChildProperties() const; inline const QList &childProperties() const; QList findChildProperties(QString name, Qt::FindChildOptions options = Qt::FindChildrenRecursively); QList findChildProperties(const QRegularExpression &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively); QtnPropertyBase *findChildProperty(QtnPropertyID id); void clearChildProperties(); bool addChildProperty(QtnPropertyBase *childProperty, bool moveOwnership = true, int index = -1); bool removeChildProperty(QtnPropertyBase *childProperty); // cloning QtnPropertySet *createNew(QObject *parentForNew) const; QtnPropertySet *createCopy(QObject *parentForCopy) const; // copy values bool copyValues(QtnPropertySet *propertySetCopyFrom, QtnPropertyState ignoreMask = QtnPropertyStateNone); // JSON support bool fromJson(const QJsonObject &jsonObject, QtnPropertyChangeReason reason = QtnPropertyChangeReasonChildren); bool toJson(QJsonObject &jsonObject) const; public: // casts virtual QtnPropertySet *asPropertySet() override; virtual const QtnPropertySet *asPropertySet() const override; protected: virtual void doReset(QtnPropertyChangeReason reason) override; virtual void updateStateInherited(bool force) override; // cloning implementation virtual QtnPropertySet *createNewImpl(QObject *parentForNew) const; virtual QtnPropertySet *createCopyImpl(QObject *parentForCopy) const; // copy values virtual bool copyValuesImpl( QtnPropertySet *propertySetCopyFrom, QtnPropertyState ignoreMask); // string conversion implementation virtual bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; virtual bool toStrImpl(QString &str) const override; virtual bool fromVariantImpl( const QVariant &v, QtnPropertyChangeReason reason) override; virtual bool toVariantImpl(QVariant &v) const override; // serialization implementation virtual bool loadImpl(QDataStream &stream) override; virtual bool saveImpl(QDataStream &stream) const override; private: void findChildPropertiesRecursive( const QString &name, QList &result); void findChildPropertiesRecursive( const QRegularExpression &re, QList &result); bool toStrWithPrefix(QString &str, const QString &prefix) const; private: CompareFunc m_compareFunc; QList m_childProperties; SortOrder m_childrenOrder; }; QtnPropertySet::SortOrder QtnPropertySet::childrenOrder() const { return m_childrenOrder; } const QtnPropertySet::CompareFunc &QtnPropertySet::compareFunc() const { return m_compareFunc; } bool QtnPropertySet::hasChildProperties() const { return !m_childProperties.empty(); } const QList &QtnPropertySet::childProperties() const { return m_childProperties; } Q_DECLARE_METATYPE(QtnPropertySet *) template T *qtnCreateProperty(QtnPropertySet *parent, QString name) { auto property = new T(parent); property->setName(name); parent->addChildProperty(property); return property; } template T *qtnCreateProperty(QtnPropertySet *parent) { auto property = new T(parent); parent->addChildProperty(property); return property; } QTN_IMPORT_EXPORT void qtnAddPropertyAsChild( QObject *parent, QtnPropertyBase *child, bool moveOwnership); QTN_IMPORT_EXPORT void qtnRemovePropertyAsChild( QObject *parent, QtnPropertyBase *child); #endif // QTN_PROPERTY_SET_H ================================================ FILE: QtnProperty/PropertyUInt64.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyUInt64.h" #include "QObjectPropertySet.h" #include "Delegates/Utils/PropertyEditorAux.h" #include "Delegates/PropertyDelegateFactory.h" #include "Delegates/Utils/PropertyDelegateSliderBox.h" #include "PropertyDelegateAttrs.h" #include #include #include QtnPropertyUInt64Base::QtnPropertyUInt64Base(QObject *parent) : QtnNumericPropertyBase>(parent) { } bool QtnPropertyUInt64Base::fromStrImpl( const QString &str, QtnPropertyChangeReason reason) { bool ok = false; ValueType value = str.toULongLong(&ok); if (!ok) return false; return setValue(value, reason); } bool QtnPropertyUInt64Base::toStrImpl(QString &str) const { str = QString::number(value()); return true; } bool QtnPropertyUInt64Base::fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) { bool ok = false; ValueType value = var.toULongLong(&ok); if (!ok) return false; return setValue(value, reason); } QtnPropertyUInt64Callback::QtnPropertyUInt64Callback(QObject *parent) : QtnSinglePropertyCallback(parent) { } QtnPropertyUInt64::QtnPropertyUInt64(QObject *parent) : QtnNumericPropertyValue(parent) { } void QtnPropertyDelegateUInt64::Register(QtnPropertyDelegateFactory &factory) { factory.registerDelegateDefault(&QtnPropertyUInt64Base::staticMetaObject, &qtnCreateDelegate, qtnLineEditDelegate()); factory.registerDelegate(&QtnPropertyUInt64Base::staticMetaObject, &qtnCreateDelegate< QtnPropertyDelegateSlideBoxTyped, QtnPropertyUInt64Base>, qtnSliderBoxDelegate()); } quint64 QtnPropertyDelegateUInt64::minValue() const { return m_min.isValid() ? m_min.toULongLong() : owner().minValue(); } quint64 QtnPropertyDelegateUInt64::maxValue() const { return m_max.isValid() ? m_max.toULongLong() : owner().maxValue(); } quint64 QtnPropertyDelegateUInt64::currentValue() const { return qBound(minValue(), owner().value(), maxValue()); } QtnPropertyDelegateUInt64::QtnPropertyDelegateUInt64( QtnPropertyUInt64Base &owner) : QObject(nullptr) , QtnPropertyDelegateTyped(owner) , editor(nullptr) , reverted(false) , applied(false) { } bool QtnPropertyDelegateUInt64::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { auto keyEvent = static_cast(event); switch (keyEvent->key()) { case Qt::Key_Escape: reverted = true; updateEditor(); break; case Qt::Key_Enter: case Qt::Key_Return: applied = true; break; default: break; } } return QObject::eventFilter(obj, event); } bool QtnPropertyDelegateUInt64::acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const { if (QtnPropertyDelegateTyped:: acceptKeyPressedForInplaceEditImpl(keyEvent)) return true; return qtnAcceptForNumEdit(keyEvent, NUM_UNSIGNED_INT); } QWidget *QtnPropertyDelegateUInt64::createValueEditorImpl( QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo) { editor = createValueEditorLineEdit( parent, rect, !stateProperty()->isEditableByUser(), inplaceInfo); updateEditor(); reverted = false; applied = false; editor->installEventFilter(this); QObject::connect(editor, &QLineEdit::editingFinished, this, &QtnPropertyDelegateUInt64::onEditingFinished); return editor; } bool QtnPropertyDelegateUInt64::propertyValueToStrImpl(QString &strValue) const { strValue = QLocale().toString(currentValue()); strValue.append(m_suffix); return true; } void QtnPropertyDelegateUInt64::applyAttributesImpl( const QtnPropertyDelegateInfo &info) { info.loadAttribute(qtnSuffixAttr(), m_suffix); m_min = info.attributes.value(qtnMinAttr()); m_max = info.attributes.value(qtnMaxAttr()); fixMinMaxVariant(m_min, m_max); } void QtnPropertyDelegateUInt64::onEditingFinished() { bool ok = false; if (!reverted && (applied || !stateProperty()->isMultiValue())) { auto str = editor->text().trimmed(); if (!m_suffix.isEmpty() && str.endsWith(m_suffix)) { str = str.left(str.length() - m_suffix.length()).trimmed(); } QLocale locale; str.remove(locale.groupSeparator()); auto value = locale.toULongLong(str, &ok); if (!ok) { value = str.toULongLong(&ok); } ok = ok && value >= minValue() && value <= maxValue(); if (ok) owner().setValue(value, editReason()); } if (!ok) updateEditor(); reverted = false; applied = false; } void QtnPropertyDelegateUInt64::updateEditor() { if (stateProperty()->isMultiValue()) { editor->clear(); } else { QString str; propertyValueToStrImpl(str); str.remove(QLocale().groupSeparator()); editor->setText(str); editor->selectAll(); } } ================================================ FILE: QtnProperty/PropertyUInt64.h ================================================ /******************************************************************************* Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "Auxiliary/PropertyTemplates.h" #include "Delegates/Utils/PropertyDelegateMisc.h" class QTN_IMPORT_EXPORT QtnPropertyUInt64Base : public QtnNumericPropertyBase> { Q_OBJECT private: QtnPropertyUInt64Base(const QtnPropertyUInt64Base &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyUInt64Base(QObject *parent); protected: // string conversion implementation virtual bool fromStrImpl( const QString &str, QtnPropertyChangeReason reason) override; virtual bool toStrImpl(QString &str) const override; // variant conversion implementation virtual bool fromVariantImpl( const QVariant &var, QtnPropertyChangeReason reason) override; P_PROPERTY_DECL_MEMBER_OPERATORS(QtnPropertyUInt64Base) }; P_PROPERTY_DECL_ALL_OPERATORS(QtnPropertyUInt64Base, quint64) class QTN_IMPORT_EXPORT QtnPropertyUInt64Callback : public QtnSinglePropertyCallback { Q_OBJECT private: QtnPropertyUInt64Callback( const QtnPropertyUInt64Callback &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyUInt64Callback(QObject *parent); P_PROPERTY_DECL_MEMBER_OPERATORS2( QtnPropertyUInt64Callback, QtnPropertyUInt64Base) }; class QTN_IMPORT_EXPORT QtnPropertyUInt64 : public QtnNumericPropertyValue { Q_OBJECT private: QtnPropertyUInt64(const QtnPropertyUInt64 &other) Q_DECL_EQ_DELETE; public: explicit QtnPropertyUInt64(QObject *parent); P_PROPERTY_DECL_MEMBER_OPERATORS2(QtnPropertyUInt64, QtnPropertyUInt64Base) }; class QLineEdit; class QTN_IMPORT_EXPORT QtnPropertyDelegateUInt64 : public QObject , public QtnPropertyDelegateTyped { Q_OBJECT Q_DISABLE_COPY(QtnPropertyDelegateUInt64) QString m_suffix; QVariant m_min; QVariant m_max; public: QtnPropertyDelegateUInt64(QtnPropertyUInt64Base &owner); static void Register(QtnPropertyDelegateFactory &factory); quint64 minValue() const; quint64 maxValue() const; quint64 currentValue() const; protected: virtual bool eventFilter(QObject *obj, QEvent *event) override; virtual bool acceptKeyPressedForInplaceEditImpl( QKeyEvent *keyEvent) const override; virtual QWidget *createValueEditorImpl(QWidget *parent, const QRect &rect, QtnInplaceInfo *inplaceInfo = nullptr) override; virtual bool propertyValueToStrImpl(QString &strValue) const override; virtual void applyAttributesImpl( const QtnPropertyDelegateInfo &info) override; private: void onEditingFinished(); private: void updateEditor(); QLineEdit *editor; bool reverted; bool applied; }; ================================================ FILE: QtnProperty/PropertyView.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016, 2020 Alex Zhondin Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyView.h" #include "Utils/InplaceEditing.h" #include "Utils/QtnConnections.h" #include "Delegates/Utils/PropertyDelegateMisc.h" #include #include #include #include struct QtnPropertyView::Item { QtnPropertyBase *property; std::unique_ptr delegate; int level; Item *parent; std::vector> children; QtnConnections connections; Item(); inline bool collapsed() const; }; struct QtnPropertyView::VisibleItem { Item *item; int level; bool hasChildren; mutable QList subItems; mutable bool subItemsValid; VisibleItem(); }; class QtnPainterState { public: QtnPainterState(QPainter &p); ~QtnPainterState(); private: QPainter &m_p; }; extern void set_smaller_text_osx(QWidget *w); QtnPropertyView::QtnPropertyView(QWidget *parent, QtnPropertySet *propertySet) : QAbstractScrollArea(parent) , m_propertySet(propertySet) , m_activeProperty(nullptr) , m_delegateFactory(&QtnPropertyDelegateFactory::staticInstance()) , m_visibleItemsValid(false) , m_grabMouseSubItem(nullptr) , m_style(QtnPropertyViewStyleLiveSplit) , m_itemHeight(0) , m_itemHeightSpacing(6) , m_valueLeftMargin(0) , m_splitRatio(0.5f) , m_lastChangeReason(0) , m_stopInvalidate(0) , m_mouseAtSplitter(false) , m_mouseCaptured(false) , m_accessibilityProxy(nullptr) { set_smaller_text_osx(this); setFocusPolicy(Qt::StrongFocus); viewport()->setMouseTracking(true); updateStyleStuff(); updateItemsTree(); } QtnPropertyView::~QtnPropertyView() { // destruct everything } QtnAccessibilityProxy *QtnPropertyView::accessibilityProxy() { if (!m_accessibilityProxy) m_accessibilityProxy = new QtnAccessibilityProxy(this); return m_accessibilityProxy; } void QtnPropertyView::onActivePropertyDestroyed() { m_activeProperty = nullptr; emit activePropertyChanged(m_activeProperty); viewport()->update(); } void QtnPropertyView::onEditedPropertyWillChange( QtnPropertyChangeReason reason, QtnPropertyValuePtr newValue, int typeId) { if (!(reason & QtnPropertyChangeReasonEdit)) { return; } Q_ASSERT(nullptr != qobject_cast(sender())); if (reason & QtnPropertyChangeReasonValue) { auto property = static_cast(sender()); emit beforePropertyEdited(property, newValue, typeId); } if (reason & QtnPropertyChangeReasonLockToggled) { auto property = static_cast(sender()); emit beforePropertyLockToggled(property); } } void QtnPropertyView::onEditedPropertyDidChange(QtnPropertyChangeReason reason) { if (!(reason & QtnPropertyChangeReasonEdit)) { return; } Q_ASSERT(nullptr != qobject_cast(sender())); if (reason & QtnPropertyChangeReasonValue) { auto property = static_cast(sender()); emit propertyEdited(property); } if (reason & QtnPropertyChangeReasonLockToggled) { auto property = static_cast(sender()); emit propertyLockToggled(property); } } void QtnPropertyView::setPropertySet(QtnPropertySet *newPropertySet) { if (newPropertySet == m_propertySet) return; if (m_propertySet) { QObject::disconnect(m_propertySet, &QtnPropertyBase::destroyed, this, &QtnPropertyView::onPropertySetDestroyed); } m_propertySet = newPropertySet; if (m_propertySet) { QObject::connect(m_propertySet, &QtnPropertyBase::destroyed, this, &QtnPropertyView::onPropertySetDestroyed); } updateItemsTree(); } QtnPropertyBase *QtnPropertyView::getPropertyParent( const QtnPropertyBase *property) const { auto item = findItem(m_itemsTree.get(), property); if (nullptr != item && nullptr != item->parent) return item->parent->property; return nullptr; } bool QtnPropertyView::setActiveProperty( QtnPropertyBase *newActiveProperty, bool ensureVisible) { if (m_activeProperty == newActiveProperty) return false; qtnStopInplaceEdit(); if (ensureVisible) this->ensureVisible(newActiveProperty); if (!newActiveProperty) { setActivePropertyInternal(nullptr); return true; } int index = visibleItemIndexByProperty(newActiveProperty); if (index < 0) return false; setActivePropertyInternal(newActiveProperty); return true; } bool QtnPropertyView::setActiveProperty(int index, bool ensureVisible) { if (index < 0) index = 0; if (nullptr == m_propertySet) return false; auto &cp = m_propertySet->childProperties(); if (cp.isEmpty()) return false; if (index >= cp.size()) index = cp.size() - 1; return setActiveProperty(cp.at(index), ensureVisible); } bool QtnPropertyView::ensureVisible(const QtnPropertyBase *property) { if (!property) return false; int index = visibleItemIndexByProperty(property); return ensureVisibleItemByIndex(index); } bool QtnPropertyView::setItemHeightSpacing(quint32 itemHeightSpacing) { m_itemHeightSpacing = itemHeightSpacing; updateStyleStuff(); return true; } void QtnPropertyView::setPropertyViewStyle(QtnPropertyViewStyle style) { m_style = style; } void QtnPropertyView::addPropertyViewStyle(QtnPropertyViewStyle style) { setPropertyViewStyle(propertyViewStyle() | style); } void QtnPropertyView::removePropertyViewStyle(QtnPropertyViewStyle style) { setPropertyViewStyle(propertyViewStyle() & ~style); } QtnPropertyBase *QtnPropertyView::getPropertyAt( const QPoint &position, QRect *out_rect) { int index = visibleItemIndexByPoint(position); if (index >= 0) { if (nullptr != out_rect) { *out_rect = visibleItemRect(index); } return m_visibleItems[index].item->property; } return nullptr; } int QtnPropertyView::valueLeftMargin() const { return m_valueLeftMargin; } bool QtnPropertyView::isMouseCaptured() const { return m_mouseCaptured || m_rubberBand; } void QtnPropertyView::connectPropertyToEdit( QtnPropertyBase *property, QtnConnections &outConnections) { Q_ASSERT(nullptr != property); outConnections.push_back( QObject::connect(property, &QtnPropertyBase::propertyWillChange, this, &QtnPropertyView::onEditedPropertyWillChange)); outConnections.push_back( QObject::connect(property, &QtnPropertyBase::propertyDidChange, this, &QtnPropertyView::onEditedPropertyDidChange)); } void QtnPropertyView::paintEvent(QPaintEvent *e) { Q_UNUSED(e); validateVisibleItems(); if (m_visibleItems.isEmpty()) { return; } int firstVisibleItemIndex = qMin(verticalScrollBar()->value() / m_itemHeight, (m_visibleItems.size() - 1)); int lastVisibleItemIndex = qMin( ((verticalScrollBar()->value() + viewport()->height()) / m_itemHeight) + 1, (m_visibleItems.size() - 1)); auto viewPortRect = viewport()->rect(); QRect itemRect = viewPortRect; itemRect.setTop( firstVisibleItemIndex * m_itemHeight - verticalScrollBar()->value()); itemRect.setBottom(itemRect.top() + m_itemHeight); QStylePainter painter(viewport()); QPen splitterPen; splitterPen.setColor(this->palette().color(QPalette::Mid)); splitterPen.setStyle(Qt::DotLine); for (int i = firstVisibleItemIndex; i <= lastVisibleItemIndex; ++i) { const VisibleItem &vItem = m_visibleItems[i]; drawItem(painter, itemRect, vItem); auto delegate = vItem.item->delegate.get(); Q_ASSERT(delegate); // cannot be null if (delegate->isSplittable()) { painter.save(); splitterPen.setDashOffset(itemRect.top()); painter.setPen(splitterPen); painter.drawLine(splitPosition(), itemRect.top(), splitPosition(), itemRect.bottom()); painter.restore(); } itemRect.translate(0, m_itemHeight); } } void QtnPropertyView::drawItem( QStylePainter &painter, const QRect &rect, const VisibleItem &vItem) const { auto delegate = vItem.item->delegate.get(); Q_ASSERT(delegate); // cannot be null QMargins margins(m_valueLeftMargin + rect.height() * vItem.level, 0, 0, 0); bool isActive = (m_activeProperty == vItem.item->property); QtnDrawContext drawContext{ &painter, this, rect, margins, splitPosition(), isActive, vItem.hasChildren }; // create sub-items if not initialized if (!vItem.subItemsValid) { Q_ASSERT(vItem.subItems.isEmpty()); delegate->createSubItems(drawContext, vItem.subItems); vItem.subItemsValid = true; } // draw sub-items for (const auto &subItem : vItem.subItems) { subItem.draw(drawContext); } } void QtnPropertyView::changeActivePropertyByIndex(int index) { QtnPropertyBase *newActiveProperty = (index < 0) ? nullptr : m_visibleItems[index].item->property; setActiveProperty(newActiveProperty); ensureVisibleItemByIndex(index); } QtnPropertyBase *QtnPropertyView::visiblePropertyAtPoint( const QPoint &pos) const { int index = visibleItemIndexByPoint(pos); if (index < 0) return nullptr; return m_visibleItems[index].item->property; } int QtnPropertyView::visibleItemIndexByPoint(const QPoint &pos) const { int index = (verticalScrollBar()->value() + pos.y()) / m_itemHeight; if (index >= m_visibleItems.size()) return -1; return index; } int QtnPropertyView::visibleItemIndexByProperty( const QtnPropertyBase *property) const { validateVisibleItems(); for (int i = 0, n = m_visibleItems.size(); i < n; ++i) if (m_visibleItems[i].item->property == property) return i; return -1; } QRect QtnPropertyView::visibleItemRect(int index) const { Q_ASSERT(index >= 0 && index < m_visibleItems.size()); QRect rect = viewport()->rect(); rect.setTop(index * m_itemHeight - verticalScrollBar()->value()); rect.setHeight(m_itemHeight); return rect; } QRect QtnPropertyView::propertyActionRect( QtnPropertyBase *property, int actionIndex) { if (!property) return QRect(); int index = visibleItemIndexByProperty(property); if (index < 0) return QRect(); const auto &item = m_visibleItems[index]; if (!item.subItemsValid) return QRect(); if (actionIndex < 0 || actionIndex >= item.subItems.size()) return QRect(); return item.subItems[actionIndex].rect; } bool QtnPropertyView::handleMouseEvent(int index, QEvent *e, QPoint mousePos) { if (index < 0) { deactivateSubItems(); return false; } QtnEventContext context{ e, this }; return handleEvent(context, m_visibleItems[index], mousePos); } void QtnPropertyView::resizeEvent(QResizeEvent *e) { Q_UNUSED(e); qtnStopInplaceEdit(); invalidateSubItems(); updateVScrollbar(); } static const int TOLERANCE = 3; void QtnPropertyView::mousePressEvent(QMouseEvent *e) { m_mouseCaptured = false; if (e->button() == Qt::RightButton) { auto property = getPropertyAt(e->pos()); setActiveProperty(property, true); QAbstractScrollArea::mousePressEvent(e); return; } if (e->button() != Qt::LeftButton) { QAbstractScrollArea::mousePressEvent(e); return; } int index = visibleItemIndexByPoint(e->pos()); bool isSplittableItem = index >= 0 ? m_visibleItems.at(index).item->delegate->isSplittable() : false; if (isSplittableItem && qAbs(e->x() - splitPosition()) < TOLERANCE) { m_rubberBand.reset(new QRubberBand(QRubberBand::Line, this)); QRect rect = viewport()->rect(); rect.setLeft(e->x()); rect.setRight(e->x()); m_rubberBand->setGeometry(rect); m_rubberBand->show(); } else { if (index >= 0) { changeActivePropertyByIndex(index); m_mouseCaptured = handleMouseEvent(index, e, e->pos()); } } QAbstractScrollArea::mousePressEvent(e); } void QtnPropertyView::mouseReleaseEvent(QMouseEvent *e) { if (e->button() != Qt::LeftButton) { QAbstractScrollArea::mouseReleaseEvent(e); return; } if (m_rubberBand) { m_rubberBand = nullptr; // update split ratio QRect rect = viewport()->rect(); updateSplitRatio((float) (e->x() - rect.left()) / (float) rect.width()); } else { handleMouseEvent(visibleItemIndexByPoint(e->pos()), e, e->pos()); emit mouseReleased(e); } QAbstractScrollArea::mouseReleaseEvent(e); m_mouseCaptured = false; } void QtnPropertyView::mouseMoveEvent(QMouseEvent *e) { if (m_rubberBand) { if (e->buttons() == Qt::LeftButton) { QRect rect = viewport()->rect(); rect.setLeft(e->x()); rect.setRight(e->x()); m_rubberBand->setGeometry(rect); if (m_style & QtnPropertyViewStyleLiveSplit) { // update split ratio QRect rect = viewport()->rect(); updateSplitRatio( (float) (e->x() - rect.left()) / (float) rect.width()); } } } else { int index = visibleItemIndexByPoint(e->pos()); bool isSplittable = index >= 0 ? m_visibleItems.at(index).item->delegate->isSplittable() : false; bool atSplitterPos = isSplittable && qAbs(e->x() - splitPosition()) < TOLERANCE; if (!handleMouseEvent(index, e, e->pos())) { if (atSplitterPos) { if (!m_mouseAtSplitter) { m_mouseAtSplitter = true; setCursor(Qt::SplitHCursor); } } if (e->buttons() & Qt::LeftButton) changeActivePropertyByIndex(index); } if (!atSplitterPos && m_mouseAtSplitter) { m_mouseAtSplitter = false; unsetCursor(); } } QAbstractScrollArea::mouseMoveEvent(e); } void QtnPropertyView::mouseDoubleClickEvent(QMouseEvent *e) { if (!m_rubberBand) { handleMouseEvent(visibleItemIndexByPoint(e->pos()), e, e->pos()); QAbstractScrollArea::mouseDoubleClickEvent(e); } } bool QtnPropertyView::viewportEvent(QEvent *e) { switch (e->type()) { case QEvent::StyleChange: updateStyleStuff(); break; case QEvent::ToolTip: { QHelpEvent *helpEvent = static_cast(e); tooltipEvent(helpEvent); break; } case QEvent::Leave: deactivateSubItems(); break; default:; // do nothing } return QAbstractScrollArea::viewportEvent(e); } void QtnPropertyView::scrollContentsBy(int dx, int dy) { if (dx != 0 || dy != 0) { qtnStopInplaceEdit(); invalidateSubItems(); } QAbstractScrollArea::scrollContentsBy(dx, dy); } void QtnPropertyView::keyPressEvent(QKeyEvent *e) { validateVisibleItems(); if (m_visibleItems.empty()) { QAbstractScrollArea::keyPressEvent(e); return; } QWidget *inplaceEditor = qtnGetInplaceEdit(); if (inplaceEditor) { int key = e->key(); if (key == Qt::Key_Escape || key == Qt::Key_Return || key == Qt::Key_Enter) { qtnStopInplaceEdit(); // eat event e->accept(); } return; } switch (e->key()) { case Qt::Key_Home: { // go to first item changeActivePropertyByIndex(0); break; } case Qt::Key_End: { // go to last item changeActivePropertyByIndex(m_visibleItems.size() - 1); break; } case Qt::Key_Up: { // go to previous item int index = visibleItemIndexByProperty(activeProperty()); if (index < 0) changeActivePropertyByIndex(0); else changeActivePropertyByIndex(qMax(0, index - 1)); break; } case Qt::Key_Down: { // go to next item int index = visibleItemIndexByProperty(activeProperty()); if (index < 0) changeActivePropertyByIndex(0); else changeActivePropertyByIndex( qMin(m_visibleItems.size() - 1, index + 1)); break; } case Qt::Key_PageUp: { // go to previous page int index = visibleItemIndexByProperty(activeProperty()); if (index < 0) changeActivePropertyByIndex(0); else { int itemsPerPage = qMax(viewport()->rect().height() / m_itemHeight, 1); changeActivePropertyByIndex(qMax(0, index - itemsPerPage)); } break; } case Qt::Key_PageDown: { // go to next page int index = visibleItemIndexByProperty(activeProperty()); if (index < 0) changeActivePropertyByIndex(0); else { int itemsPerPage = qMax(viewport()->rect().height() / m_itemHeight, 1); changeActivePropertyByIndex( qMin(m_visibleItems.size() - 1, index + itemsPerPage)); } break; } case Qt::Key_Left: { // go to parent item or collapse int index = visibleItemIndexByProperty(activeProperty()); if (index < 0) changeActivePropertyByIndex(0); else { const VisibleItem &vItem = m_visibleItems[index]; if (vItem.hasChildren && !vItem.item->collapsed()) { // collapse opened property vItem.item->property->addState(QtnPropertyStateCollapsed); } else if (vItem.item->parent) { // activate parent property setActiveProperty(vItem.item->parent->property, true); } } break; } case Qt::Key_Right: { // go to child item or expand int index = visibleItemIndexByProperty(activeProperty()); if (index < 0) changeActivePropertyByIndex(0); else { const VisibleItem &vItem = m_visibleItems[index]; if (vItem.hasChildren && vItem.item->collapsed()) { // expand closed property vItem.item->property->removeState( QtnPropertyStateCollapsed); } else if (vItem.hasChildren) { // activate child property setActiveProperty( vItem.item->children.front()->property, true); } } break; } default: { int index = visibleItemIndexByProperty(activeProperty()); if (index >= 0) { QtnEventContext context{ e, this }; if (handleEvent(context, m_visibleItems[index], QPoint())) { // eat event e->accept(); return; } } // process by default QAbstractScrollArea::keyPressEvent(e); } } } void QtnPropertyView::wheelEvent(QWheelEvent *e) { bool processed = handleMouseEvent(visibleItemIndexByPoint(e->pos()), e, e->pos()); if (processed) return; QAbstractScrollArea::wheelEvent(e); } void QtnPropertyView::tooltipEvent(QHelpEvent *e) { if (!handleMouseEvent(visibleItemIndexByPoint(e->pos()), e, e->pos())) { QToolTip::hideText(); } } bool QtnPropertyView::handleEvent( QtnEventContext &context, VisibleItem &vItem, QPoint mousePos) { if (!vItem.subItemsValid) return false; if (0 == m_stopInvalidate++) m_lastChangeReason = QtnPropertyChangeReason(0); bool result; // process event if (m_grabMouseSubItem) result = m_grabMouseSubItem->event(context); else { result = false; // update list of sub items under cursor QList activeSubItems; // make list of new active sub items for (auto &subItem : vItem.subItems) { if (mousePos.isNull() || subItem.rect.contains(mousePos)) { subItem.activate(this, mousePos); activeSubItems.append(&subItem); } } // deactivate old sub items for (auto activeSubItem : m_activeSubItems) { activeSubItem->deactivate(this, mousePos); } // adopt new active sub items m_activeSubItems.swap(activeSubItems); // process event for (auto activeSubItem : m_activeSubItems) { if (activeSubItem->event(context)) { result = true; break; } } } if (--m_stopInvalidate == 0) updateWithReason(m_lastChangeReason); return result; } QtnPropertyView::Item::Item() : property(nullptr) , level(0) , parent(nullptr) { } bool QtnPropertyView::Item::collapsed() const { return property->isCollapsed(); } bool QtnPropertyView::grabMouseForSubItem(QtnSubItem *subItem, QPoint mousePos) { Q_ASSERT(!m_grabMouseSubItem); if (m_grabMouseSubItem) return false; viewport()->grabMouse(); m_grabMouseSubItem = subItem; m_grabMouseSubItem->grabMouse(this, mousePos); return true; } bool QtnPropertyView::releaseMouseForSubItem( QtnSubItem *subItem, QPoint mousePos) { Q_UNUSED(subItem); Q_ASSERT(m_grabMouseSubItem == subItem); if (!m_grabMouseSubItem) return false; m_grabMouseSubItem->releaseMouse(this, mousePos); m_grabMouseSubItem = nullptr; viewport()->releaseMouse(); return true; } void QtnPropertyView::updateItemsTree() { m_itemsTree.reset(createItemsTree(m_propertySet)); invalidateVisibleItems(); } QtnPropertyView::Item *QtnPropertyView::createItemsTree( QtnPropertyBase *rootProperty) { if (!rootProperty) return nullptr; auto item = new Item; item->property = rootProperty; auto &connections = item->connections; connections.push_back( QObject::connect(rootProperty, &QtnPropertyBase::propertyDidChange, this, [item, this](QtnPropertyChangeReason reason) { onPropertyDidChange(reason, item); })); setupItemDelegate(item); return item; } void QtnPropertyView::setActivePropertyInternal(QtnPropertyBase *property) { disconnectActiveProperty(); m_activeProperty = property; emit activePropertyChanged(m_activeProperty); viewport()->update(); connectActiveProperty(); } void QtnPropertyView::invalidateVisibleItems() { deactivateSubItems(); m_visibleItemsValid = false; m_visibleItems.clear(); viewport()->update(); } void QtnPropertyView::validateVisibleItems() const { if (m_visibleItemsValid) return; fillVisibleItems( m_itemsTree.get(), (m_style & QtnPropertyViewStyleShowRoot) ? 0 : -1); updateVScrollbar(); m_visibleItemsValid = true; } void QtnPropertyView::fillVisibleItems(Item *item, int level) const { if (!item) return; // process children only for negative levels if (level < 0) { // process children for (auto &child : item->children) { fillVisibleItems(child.get(), level + 1); } return; } // skip not accepted items if (!acceptItem(*item)) return; VisibleItem vItem; vItem.item = item; vItem.level = level; if (item->collapsed()) { // check if item has any child for (auto &child : item->children) { if (acceptItem(*child.get())) { vItem.hasChildren = true; break; } } // add item and quit m_visibleItems.append(vItem); return; } // add item m_visibleItems.append(vItem); // save just added item index int index = m_visibleItems.size() - 1; // process children for (auto &child : item->children) { fillVisibleItems(child.get(), level + 1); } // if we add something -> current item has children if (index < (m_visibleItems.size() - 1)) m_visibleItems[index].hasChildren = true; } bool QtnPropertyView::acceptItem(const Item &item) const { return item.property->isVisible(); } void QtnPropertyView::updateVScrollbar() const { int viewportHeight = viewport()->height(); int virtualHeight = m_itemHeight * m_visibleItems.size(); verticalScrollBar()->setSingleStep(m_itemHeight); verticalScrollBar()->setPageStep(viewportHeight); verticalScrollBar()->setRange( 0, qMax(0, virtualHeight - viewportHeight + 2)); } void QtnPropertyView::updateStyleStuff() { QFontMetrics fm(font()); m_itemHeight = fm.height() + m_itemHeightSpacing; m_propertySetBackdroundColor = m_linesColor = palette().color(QPalette::Button); m_valueLeftMargin = style()->pixelMetric(QStyle::PM_ButtonMargin); } bool QtnPropertyView::ensureVisibleItemByIndex(int index) { if (index < 0) return false; int vItemTop = index * m_itemHeight; int vItemBottom = vItemTop + m_itemHeight; QRect rect = viewport()->rect(); int scrollPos = verticalScrollBar()->value(); if (vItemTop < scrollPos) scrollPos = vItemTop; else if (vItemBottom > scrollPos + rect.height()) scrollPos = vItemBottom - rect.height(); else return false; verticalScrollBar()->setValue(scrollPos); return true; } void QtnPropertyView::invalidateSubItems() { deactivateSubItems(); for (auto &item : m_visibleItems) { item.subItemsValid = false; item.subItems.clear(); } } void QtnPropertyView::deactivateSubItems() { if (m_grabMouseSubItem) { viewport()->releaseMouse(); m_grabMouseSubItem = nullptr; } for (auto subItem : m_activeSubItems) subItem->deactivate(this, QPoint()); m_activeSubItems.clear(); QToolTip::hideText(); } int QtnPropertyView::splitPosition() const { return (int) ((float) viewport()->rect().width() * m_splitRatio); } void QtnPropertyView::updateSplitRatio(float splitRatio) { m_splitRatio = qBound(0.f, splitRatio, 1.f); // firce to regenerate sub-items invalidateSubItems(); // repaint viewport()->update(); } void QtnPropertyView::connectActiveProperty() { if (nullptr != m_activeProperty) { QObject::connect(m_activeProperty, &QObject::destroyed, this, &QtnPropertyView::onActivePropertyDestroyed); } } void QtnPropertyView::disconnectActiveProperty() { if (nullptr != m_activeProperty) { QObject::disconnect(m_activeProperty, &QObject::destroyed, this, &QtnPropertyView::onActivePropertyDestroyed); } } void QtnPropertyView::onPropertyDidChange( QtnPropertyChangeReason reason, Item *item) { if (!reason) return; if (reason & QtnPropertyChangeReasonUpdateDelegate) { setupItemDelegate(item); } if (m_stopInvalidate) { m_lastChangeReason |= reason; } else { updateWithReason(reason); } emit propertiesChanged(reason); } QtnPropertyView::Item *QtnPropertyView::findItem( Item *currentItem, const QtnPropertyBase *property) const { if (nullptr != currentItem && nullptr != property) { if (property == currentItem->property) return currentItem; for (auto &item : currentItem->children) { auto found = findItem(item.get(), property); if (nullptr != found) return found; } } return nullptr; } void QtnPropertyView::setupItemDelegate(Item *item) { auto property = item->property; auto delegate = m_delegateFactory.createDelegate(*property); Q_ASSERT(delegate); // should always return non-null item->delegate.reset(delegate); item->children.clear(); // apply attributes auto delegateInfo = property->delegateInfo(); if (delegateInfo) { delegate->applyAttributes(*delegateInfo); } // process delegate subproperties for (int i = 0, n = delegate->subPropertyCount(); i < n; ++i) { auto child = delegate->subProperty(i); Q_ASSERT(child); auto childItem = createItemsTree(child); childItem->parent = item; item->children.emplace_back(childItem); } } QtnPropertyView::VisibleItem::VisibleItem() : item(nullptr) , level(0) , hasChildren(false) , subItemsValid(false) { } void QtnPropertyView::onPropertySetDestroyed() { m_propertySet = nullptr; updateItemsTree(); } void QtnPropertyView::updateWithReason(QtnPropertyChangeReason reason) { if (reason & QtnPropertyChangeReasonChildren) { updateItemsTree(); } else if (reason & (QtnPropertyChangeReasonState | QtnPropertyChangeReasonUpdateDelegate)) { invalidateVisibleItems(); } else { viewport()->update(); } } QtnPainterState::QtnPainterState(QPainter &p) : m_p(p) { m_p.save(); } QtnPainterState::~QtnPainterState() { m_p.restore(); } ================================================ FILE: QtnProperty/PropertyView.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_PROPERTYVIEW_H #define QTN_PROPERTYVIEW_H #include "FunctionalHelpers.h" #include "Delegates/PropertyDelegateFactory.h" #include "Utils/AccessibilityProxy.h" #include #include class QRubberBand; class QHelpEvent; class QtnConnections; enum QtnPropertyViewStyleFlag { QtnPropertyViewStyleNone = 0x0000, QtnPropertyViewStyleShowRoot = 0x0001, QtnPropertyViewStyleLiveSplit = 0x0002, QtnPropertyViewStyleDblClickActivation = 0x0004 }; Q_DECLARE_FLAGS(QtnPropertyViewStyle, QtnPropertyViewStyleFlag) Q_DECLARE_OPERATORS_FOR_FLAGS(QtnPropertyViewStyle) class QTN_IMPORT_EXPORT QtnPropertyView : public QAbstractScrollArea { Q_OBJECT Q_DISABLE_COPY(QtnPropertyView) public: explicit QtnPropertyView( QWidget *parent = nullptr, QtnPropertySet *propertySet = nullptr); virtual ~QtnPropertyView() override; inline QtnPropertyDelegateFactory *delegateFactory(); inline const QtnPropertySet *propertySet() const; inline QtnPropertySet *propertySet(); void setPropertySet(QtnPropertySet *newPropertySet); QtnPropertyBase *getPropertyParent(const QtnPropertyBase *property) const; inline QtnPropertyBase *activeProperty(); inline const QtnPropertyBase *activeProperty() const; bool setActiveProperty( QtnPropertyBase *newActiveProperty, bool ensureVisible = false); bool setActiveProperty(int index, bool ensureVisible = false); bool ensureVisible(const QtnPropertyBase *property); inline int itemHeight() const; inline quint32 itemHeightSpacing() const; bool setItemHeightSpacing(quint32 itemHeightSpacing); inline QtnPropertyViewStyle propertyViewStyle() const; void setPropertyViewStyle(QtnPropertyViewStyle style); void addPropertyViewStyle(QtnPropertyViewStyle style); void removePropertyViewStyle(QtnPropertyViewStyle style); QtnPropertyBase *getPropertyAt( const QPoint &position, QRect *out_rect = nullptr); void connectPropertyToEdit( QtnPropertyBase *property, QtnConnections &outConnections); int valueLeftMargin() const; bool isMouseCaptured() const; public slots: QtnAccessibilityProxy *accessibilityProxy(); signals: void propertiesChanged(QtnPropertyChangeReason reason); // emits when active property has changed void activePropertyChanged(QtnPropertyBase *activeProperty); void mouseReleased(QMouseEvent *e); void beforePropertyEdited( QtnPropertyBase *property, QtnPropertyValuePtr newValue, int typeId); void propertyEdited(QtnPropertyBase *property); void beforePropertyLockToggled(QtnPropertyBase *property); void propertyLockToggled(QtnPropertyBase *property); private: void onActivePropertyDestroyed(); void onEditedPropertyWillChange(QtnPropertyChangeReason reason, QtnPropertyValuePtr newValue, int typeId); void onEditedPropertyDidChange(QtnPropertyChangeReason reason); protected: void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; void mousePressEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseDoubleClickEvent(QMouseEvent *e) override; bool viewportEvent(QEvent *e) override; void scrollContentsBy(int dx, int dy) override; void keyPressEvent(QKeyEvent *e) override; void wheelEvent(QWheelEvent *e) override; void tooltipEvent(QHelpEvent *e); private: struct Item; struct VisibleItem; private: void updateItemsTree(); Item *createItemsTree(QtnPropertyBase *rootProperty); void setActivePropertyInternal(QtnPropertyBase *property); void invalidateVisibleItems(); void validateVisibleItems() const; void fillVisibleItems(Item *item, int level) const; bool acceptItem(const Item &item) const; void drawItem(QStylePainter &painter, const QRect &rect, const VisibleItem &vItem) const; void changeActivePropertyByIndex(int index); QtnPropertyBase *visiblePropertyAtPoint(const QPoint &pos) const; int visibleItemIndexByPoint(const QPoint &pos) const; int visibleItemIndexByProperty(const QtnPropertyBase *property) const; QRect visibleItemRect(int index) const; QRect propertyActionRect(QtnPropertyBase *property, int actionIndex); bool handleMouseEvent(int index, QEvent *e, QPoint mousePos); bool handleEvent( QtnEventContext &context, VisibleItem &vItem, QPoint mousePos); bool grabMouseForSubItem(QtnSubItem *subItem, QPoint mousePos); bool releaseMouseForSubItem(QtnSubItem *subItem, QPoint mousePos); void updateVScrollbar() const; void updateStyleStuff(); bool ensureVisibleItemByIndex(int index); void invalidateSubItems(); void deactivateSubItems(); int splitPosition() const; void updateSplitRatio(float splitRatio); void connectActiveProperty(); void disconnectActiveProperty(); void onPropertyDidChange(QtnPropertyChangeReason reason, Item *item); void onPropertySetDestroyed(); void updateWithReason(QtnPropertyChangeReason reason); Item *findItem(Item *currentItem, const QtnPropertyBase *property) const; void setupItemDelegate(Item *item); private: QtnPropertySet *m_propertySet; QtnPropertyBase *m_activeProperty; QtnPropertyDelegateFactory m_delegateFactory; std::unique_ptr m_itemsTree; mutable QList m_visibleItems; mutable bool m_visibleItemsValid; QList m_activeSubItems; QtnSubItem *m_grabMouseSubItem; QtnPropertyViewStyle m_style; int m_itemHeight; quint32 m_itemHeightSpacing; int m_valueLeftMargin; QColor m_linesColor; QColor m_propertySetBackdroundColor; float m_splitRatio; std::unique_ptr m_rubberBand; QtnPropertyChangeReason m_lastChangeReason; unsigned m_stopInvalidate; bool m_mouseAtSplitter; bool m_mouseCaptured; friend class QtnAccessibilityProxy; QtnAccessibilityProxy *m_accessibilityProxy; friend struct QtnEventContext; }; QtnPropertyDelegateFactory *QtnPropertyView::delegateFactory() { return &m_delegateFactory; } const QtnPropertySet *QtnPropertyView::propertySet() const { return m_propertySet; } QtnPropertySet *QtnPropertyView::propertySet() { return m_propertySet; } QtnPropertyBase *QtnPropertyView::activeProperty() { return m_activeProperty; } const QtnPropertyBase *QtnPropertyView::activeProperty() const { return m_activeProperty; } int QtnPropertyView::itemHeight() const { return m_itemHeight; } quint32 QtnPropertyView::itemHeightSpacing() const { return m_itemHeightSpacing; } QtnPropertyViewStyle QtnPropertyView::propertyViewStyle() const { return m_style; } #endif // QTN_PROPERTYVIEW_H ================================================ FILE: QtnProperty/PropertyWidget.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyWidget.h" #include "PropertyView.h" #include #include #include #include class QtnSplitterEventsHandler : public QObject { public: QtnSplitterEventsHandler(QObject *parent); protected: virtual bool eventFilter(QObject *obj, QEvent *event) override; }; // It's safe to call this function on any platform. // It will only have an effect on the Mac. void set_smaller_text_osx(QWidget *w) { Q_ASSERT(w != 0); // By default, none of these size attributes are set. // If any has been set explicitly, we'll leave the widget alone. if (!w->testAttribute(Qt::WA_MacMiniSize) && !w->testAttribute(Qt::WA_MacSmallSize) && !w->testAttribute(Qt::WA_MacNormalSize) && !w->testAttribute(Qt::WA_MacVariableSize)) { // make the text the 'normal' size w->setAttribute(Qt::WA_MacSmallSize); } } QtnPropertyWidget::QtnPropertyWidget(QWidget *parent) : QWidget(parent) , m_parts(QtnPropertyWidgetPartsNone) , m_layout(new QVBoxLayout(this)) , m_toolbar(0) , m_propertyView(new QtnPropertyView(this)) , m_descriptionSplitter(0) , m_descriptionPanel(0) { m_layout->setContentsMargins(0, 0, 0, 0); m_layout->setMargin(0); m_layout->setSpacing(0); set_smaller_text_osx(this); QObject::connect(m_propertyView, &QtnPropertyView::activePropertyChanged, this, &QtnPropertyWidget::setActiveProperty); updateParts(); } QtnPropertyWidget::~QtnPropertyWidget() { QObject::disconnect(m_propertyView, &QtnPropertyView::activePropertyChanged, this, &QtnPropertyWidget::setActiveProperty); } void QtnPropertyWidget::setParts(QtnPropertyWidgetParts newParts) { if (m_parts == newParts) return; m_parts = newParts; updateParts(); } const QtnPropertySet *QtnPropertyWidget::propertySet() const { return m_propertyView->propertySet(); } QtnPropertySet *QtnPropertyWidget::propertySet() { return m_propertyView->propertySet(); } void QtnPropertyWidget::setPropertySet(QtnPropertySet *newPropertySet) { if (newPropertySet == propertySet()) return; m_propertyView->setPropertySet(newPropertySet); emit propertySetChanged(); } void QtnPropertyWidget::updateParts() { // clear layout while (!m_layout->isEmpty()) { m_layout->takeAt(0); } // check toolbar // check description panel if (m_parts & QtnPropertyWidgetPartsDescriptionPanel) { if (!m_descriptionSplitter) { // create splitter Q_ASSERT(!m_descriptionPanel); QSplitter *splitter = new QSplitter(Qt::Vertical, this); // add property view splitter->addWidget(m_propertyView); // create description panel m_descriptionPanel = new QLabel(splitter); m_descriptionPanel->setTextFormat(Qt::RichText); m_descriptionPanel->setAlignment(Qt::AlignTop); m_descriptionPanel->setWordWrap(true); m_descriptionPanel->setFrameStyle(QFrame::Box | QFrame::Sunken); m_descriptionPanel->setMinimumSize( 0, 5 * QFontMetrics(font()).height() / 2); QSizePolicy p = m_descriptionPanel->sizePolicy(); p.setVerticalPolicy(QSizePolicy::Ignored); p.setHorizontalPolicy(QSizePolicy::Ignored); m_descriptionPanel->setSizePolicy(p); // set desctiption panel fixed size splitter->setStretchFactor(0, 1); splitter->setStretchFactor(1, 0); // setup DblClick handler splitter->handle(1)->installEventFilter( new QtnSplitterEventsHandler(splitter)); m_descriptionSplitter = splitter; } m_layout->addWidget(m_descriptionSplitter); } else { m_layout->addWidget(m_propertyView); if (m_descriptionSplitter) { delete m_descriptionSplitter; m_descriptionSplitter = nullptr; m_descriptionPanel = nullptr; } } } void QtnPropertyWidget::setActiveProperty(const QtnPropertyBase *activeProperty) { if (m_descriptionPanel) { if (!activeProperty) { m_descriptionPanel->setText(QString()); } else { m_descriptionPanel->setText(QStringLiteral("%1
%2") .arg(activeProperty->displayName(), activeProperty->description())); } } } QtnSplitterEventsHandler::QtnSplitterEventsHandler(QObject *parent) : QObject(parent) { } bool QtnSplitterEventsHandler::eventFilter(QObject *obj, QEvent *event) { // check input if (event->type() != QEvent::MouseButtonDblClick) return false; QMouseEvent *mouseEvent = static_cast(event); if (mouseEvent->button() != Qt::LeftButton) return false; QSplitterHandle *splitterHandle = qobject_cast(obj); if (!splitterHandle) return false; QSplitter *splitter = splitterHandle->splitter(); if (!splitter || splitter->count() < 2) return false; // change splitter sizes to make description panel occupy ideal height QWidget *bottomWidget = splitter->widget(1); QList sizes = splitter->sizes(); if (sizes.size() != 2) return false; sizes[0] += sizes[1]; sizes[1] = bottomWidget->heightForWidth(bottomWidget->size().width()); sizes[0] -= qMax(sizes[1], 0); splitter->setSizes(sizes); return true; } ================================================ FILE: QtnProperty/PropertyWidget.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_PROPERTYWIDGET_H #define QTN_PROPERTYWIDGET_H #include "Config.h" #include enum QtnPropertyWidgetPartsFlag { QtnPropertyWidgetPartsNone = 0x0000, QtnPropertyWidgetPartsToolbar = 0x0001, QtnPropertyWidgetPartsDescriptionPanel = 0x0002 }; class QtnPropertyView; class QtnPropertySet; class QtnPropertyBase; class QVBoxLayout; class QLabel; Q_DECLARE_FLAGS(QtnPropertyWidgetParts, QtnPropertyWidgetPartsFlag) Q_DECLARE_OPERATORS_FOR_FLAGS(QtnPropertyWidgetParts) class QTN_IMPORT_EXPORT QtnPropertyWidget : public QWidget { Q_OBJECT Q_DISABLE_COPY(QtnPropertyWidget) public: explicit QtnPropertyWidget(QWidget *parent = 0); virtual ~QtnPropertyWidget() override; inline QtnPropertyWidgetParts parts() const; void setParts(QtnPropertyWidgetParts newParts); const QtnPropertySet *propertySet() const; QtnPropertySet *propertySet(); void setPropertySet(QtnPropertySet *newPropertySet); inline QtnPropertyView *propertyView() const; signals: void propertySetChanged(); private: void updateParts(); void setActiveProperty(const QtnPropertyBase *activeProperty); private: QtnPropertyWidgetParts m_parts; QVBoxLayout *m_layout; QLabel *m_toolbar; QtnPropertyView *m_propertyView; QWidget *m_descriptionSplitter; QLabel *m_descriptionPanel; }; QtnPropertyWidgetParts QtnPropertyWidget::parts() const { return m_parts; } QtnPropertyView *QtnPropertyWidget::propertyView() const { return m_propertyView; } #endif // QTN_PROPERTYWIDGET_H ================================================ FILE: QtnProperty/PropertyWidgetEx.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "PropertyWidgetEx.h" #include "PropertyView.h" #include "Utils/QtnConnections.h" #include #include #include #include #include #include #include #include #include #include QtnPropertyWidgetEx::QtnPropertyWidgetEx(QWidget *parent) : QtnPropertyWidget(parent) , draggedProperty(nullptr) , mDrag(nullptr) , dropAction(Qt::IgnoreAction) , canRemove(false) { setAcceptDrops(true); propertyView()->installEventFilter(this); QObject::connect(propertyView(), &QtnPropertyView::mouseReleased, this, &QtnPropertyWidgetEx::onMouseReleased); } void QtnPropertyWidgetEx::connectDeleteAction(QAction *action, bool connect) { internalConnect( action, &QtnPropertyWidgetEx::deleteActiveProperty, connect); } void QtnPropertyWidgetEx::connectCutAction(QAction *action, bool connect) { internalConnect(action, &QtnPropertyWidgetEx::cutToClipboard, connect); } void QtnPropertyWidgetEx::connectCopyAction(QAction *action, bool connect) { internalConnect(action, &QtnPropertyWidgetEx::copyToClipboard, connect); } void QtnPropertyWidgetEx::connectPasteAction(QAction *action, bool connect) { internalConnect(action, &QtnPropertyWidgetEx::pasteFromClipboard, connect); } bool QtnPropertyWidgetEx::canDeleteActiveProperty() { return canDeleteProperty(getActiveProperty()); } bool QtnPropertyWidgetEx::canDeleteProperty(QtnPropertyBase *) { return false; } bool QtnPropertyWidgetEx::canCutToClipboard() { return false; } bool QtnPropertyWidgetEx::canCopyToClipboard() { return (nullptr != getActiveProperty()); } bool QtnPropertyWidgetEx::canPasteFromClipboard() { return dataHasSupportedFormats(QApplication::clipboard()->mimeData()) && (nullptr != getActiveProperty()); } QtnPropertyBase *QtnPropertyWidgetEx::getActiveProperty() const { return propertyView()->activeProperty(); } void QtnPropertyWidgetEx::addShortcutForAction(const QKeySequence &seq, QAction *action, QWidget *parent, Qt::ShortcutContext shortcutContext) { if (seq.isEmpty()) return; Q_ASSERT(nullptr != action); Q_ASSERT(nullptr != parent); auto shortcut = new QShortcut(seq, parent, nullptr, nullptr, shortcutContext); QObject::connect( shortcut, &QShortcut::activated, action, &QAction::trigger); } void QtnPropertyWidgetEx::onMouseReleased() { draggedProperty = nullptr; } void QtnPropertyWidgetEx::onResetTriggered() { auto activeProperty = getActiveProperty(); if (activeProperty && activeProperty->isResettable() && activeProperty->isEditableByUser()) { QtnConnections connections; propertyView()->connectPropertyToEdit(activeProperty, connections); QtnPropertyChangeReason reason = QtnPropertyChangeReasonEdit; activeProperty->reset(reason); } } void QtnPropertyWidgetEx::onLockToggleTriggered() { auto activeProperty = getActiveProperty(); if (activeProperty && activeProperty->isUnlockable() && activeProperty->isVisible()) { QtnConnections connections; propertyView()->connectPropertyToEdit(activeProperty, connections); QtnPropertyChangeReason reason = QtnPropertyChangeReasonEdit; activeProperty->toggleLock(reason); } } bool QtnPropertyWidgetEx::dataHasSupportedFormats(const QMimeData *data) { if (nullptr != data) { return data->hasText() || data->hasUrls() || data->hasColor(); } return false; } void QtnPropertyWidgetEx::deleteActiveProperty() { deleteProperty(getActiveProperty()); } void QtnPropertyWidgetEx::cutToClipboard() { copyToClipboard(); deleteActiveProperty(); } void QtnPropertyWidgetEx::copyToClipboard() { auto property = getActiveProperty(); if (nullptr != property) { auto mime = getPropertyDataForAction(property, Qt::IgnoreAction); if (nullptr != mime) QApplication::clipboard()->setMimeData(mime); } } void QtnPropertyWidgetEx::pasteFromClipboard() { auto data = QApplication::clipboard()->mimeData(); if (dataHasSupportedFormats(data)) { applyPropertyData(data, getActiveProperty(), QtnApplyPosition::None); } } void QtnPropertyWidgetEx::contextMenuEvent(QContextMenuEvent *event) { auto property = getActiveProperty(); if (!property) return; auto menu = new QMenu; int actionCount = 0; if (property->isResettable() && property->isVisible() && !property->valueIsDefault() && (!property->isUnlockable() || !property->isLocked())) { auto action = menu->addAction(tr("Reset to default")); action->setIcon(QtnPropertyDelegate::resetIcon()); action->setStatusTip( tr("Reset value of %1 to default").arg(property->displayName())); QObject::connect(action, &QAction::triggered, this, &QtnPropertyWidgetEx::onResetTriggered); actionCount++; } if (property->isUnlockable() && property->isVisible()) { auto action = menu->addAction( property->isLocked() ? tr("Unlock property") : tr("Lock property")); auto statusFmt = property->isLocked() ? tr("Unlock %1") : tr("Lock %1"); action->setStatusTip(statusFmt.arg(property->displayName())); QObject::connect(action, &QAction::triggered, this, &QtnPropertyWidgetEx::onLockToggleTriggered); actionCount++; } if (actionCount == 0) { delete menu; return; } menu->setAttribute(Qt::WA_DeleteOnClose); menu->popup(event->globalPos()); } void QtnPropertyWidgetEx::deleteProperty(QtnPropertyBase *) { // do nothing } QMimeData *QtnPropertyWidgetEx::getPropertyDataForAction( QtnPropertyBase *property, Qt::DropAction) { Q_ASSERT(nullptr != property); QString str; if (property->toStr(str)) { auto mime = new QMimeData; mime->setText(str); return mime; } return nullptr; } bool QtnPropertyWidgetEx::applyPropertyData( const QMimeData *data, QtnPropertyBase *destination, QtnApplyPosition) { if (nullptr != destination && destination->isWritable()) { QtnConnections connections; propertyView()->connectPropertyToEdit(destination, connections); Q_ASSERT(nullptr != data); QString str; if (data->hasUrls()) { QStringList list; for (auto &url : data->urls()) { if (url.isLocalFile()) list.push_back(url.toLocalFile()); else list.push_back(url.toString()); } str = list.join('\n'); } else if (data->hasColor()) { auto color = data->colorData().value(); str = color.name( (color.alpha() < 255) ? QColor::HexArgb : QColor::HexRgb); } else if (data->hasText()) { str = data->text(); } else { return false; } return destination->fromStr(str, QtnPropertyChangeReasonEdit); } return false; } bool QtnPropertyWidgetEx::eventFilter(QObject *obj, QEvent *event) { switch (event->type()) { case QEvent::MouseButtonPress: { if (draggedProperty) break; auto mevent = static_cast(event); if (mevent->button() == Qt::LeftButton) { if (propertyView()->isMouseCaptured()) { break; } dragStartPos = mevent->pos(); draggedProperty = propertyView()->getPropertyAt(dragStartPos); canRemove = canDeleteProperty(draggedProperty); return true; } break; } case QEvent::MouseMove: { if (mDrag) break; if (propertyView()->isMouseCaptured()) { break; } auto mevent = static_cast(event); if (nullptr != draggedProperty && 0 != (mevent->buttons() & Qt::LeftButton)) { if ((mevent->pos() - dragStartPos).manhattanLength() >= QApplication::startDragDistance()) { dragAndDrop(); return true; } } break; } default: break; } return QtnPropertyWidget::eventFilter(obj, event); } void QtnPropertyWidgetEx::dragEnterEvent(QDragEnterEvent *event) { if (dataHasSupportedFormats(event->mimeData())) event->acceptProposedAction(); } void QtnPropertyWidgetEx::dragMoveEvent(QDragMoveEvent *event) { if (Qt::ControlModifier == QApplication::keyboardModifiers() || !canRemove) { event->setDropAction(Qt::CopyAction); dropAction = Qt::CopyAction; } else { event->setDropAction(Qt::MoveAction); dropAction = Qt::MoveAction; } event->accept(); } void QtnPropertyWidgetEx::dropEvent(QDropEvent *event) { switch (event->dropAction()) { case Qt::MoveAction: case Qt::CopyAction: { auto view = propertyView(); auto pos = view->mapFrom(this, event->pos()); QRect rect; auto destination = view->getPropertyAt(pos, &rect); if (destination == draggedProperty) { draggedProperty = nullptr; break; } QtnApplyPosition applyPosition; if (destination == nullptr) { applyPosition = QtnApplyPosition::After; } else { int partHeight = view->itemHeight() / 3; if (QRect(rect.left(), rect.top(), rect.width(), partHeight) .contains(pos)) applyPosition = QtnApplyPosition::Before; else if (QRect(rect.left(), rect.bottom() - partHeight, rect.width(), partHeight) .contains(pos)) applyPosition = QtnApplyPosition::After; else applyPosition = QtnApplyPosition::Over; } auto data = event->mimeData(); if (dataHasSupportedFormats(data) && drop(data, destination, applyPosition)) { event->accept(); } break; } default: break; } } bool QtnPropertyWidgetEx::drop(const QMimeData *data, QtnPropertyBase *property, QtnApplyPosition applyPosition) { return applyPropertyData(data, property, applyPosition); } void QtnPropertyWidgetEx::dropEnd() { if (nullptr != draggedProperty) { if (Qt::MoveAction == dropAction) deleteProperty(draggedProperty); } } void QtnPropertyWidgetEx::onDropFinished(Qt::DropAction) { dropEnd(); draggedProperty = nullptr; mDrag = nullptr; } bool QtnPropertyWidgetEx::dragAndDrop() { dropAction = Qt::IgnoreAction; auto data = getPropertyDataForAction(draggedProperty, Qt::CopyAction); if (nullptr != data) { mDrag = new QDrag(this); mDrag->setMimeData(data); // TODO generate cursor #ifdef Q_OS_WASM QObject::connect(mDrag, &QDrag::finished, this, &QtnPropertyWidgetEx::onDropFinished); mDrag->exec(Qt::CopyAction | Qt::MoveAction); #else onDropFinished(mDrag->exec(Qt::CopyAction | Qt::MoveAction)); #endif return true; } draggedProperty = nullptr; return false; } void QtnPropertyWidgetEx::internalConnect( QAction *action, void (QtnPropertyWidgetEx::*slot)(), bool connect) { if (connect) QObject::connect(action, &QAction::triggered, this, slot); else QObject::disconnect(action, &QAction::triggered, this, slot); } QtnPropertyWidgetExDelegate::~QtnPropertyWidgetExDelegate() {} ================================================ FILE: QtnProperty/PropertyWidgetEx.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "PropertyWidget.h" class QMimeData; class QShortcut; class QDrag; enum class QtnApplyPosition { None, Before, Over, After }; struct QTN_IMPORT_EXPORT QtnPropertyWidgetExDelegate { virtual ~QtnPropertyWidgetExDelegate(); virtual bool canDeleteProperty(QtnPropertyBase *property) = 0; virtual bool canCutToClipboard() = 0; virtual bool canCopyToClipboard() = 0; virtual bool canPasteFromClipboard() = 0; virtual bool dataHasSupportedFormats(const QMimeData *data) = 0; virtual void deleteProperty(QtnPropertyBase *property) = 0; virtual QMimeData *getPropertyDataForAction( QtnPropertyBase *property, Qt::DropAction action) = 0; virtual bool applyPropertyData(const QMimeData *data, QtnPropertyBase *destination, QtnApplyPosition position) = 0; }; class QTN_IMPORT_EXPORT QtnPropertyWidgetEx : public QtnPropertyWidget , public QtnPropertyWidgetExDelegate { Q_OBJECT public: explicit QtnPropertyWidgetEx(QWidget *parent = nullptr); void connectDeleteAction(QAction *dropAction, bool connect); void connectCutAction(QAction *dropAction, bool connect); void connectCopyAction(QAction *dropAction, bool connect); void connectPasteAction(QAction *dropAction, bool connect); bool canDeleteActiveProperty(); virtual bool canDeleteProperty(QtnPropertyBase *property) override; virtual bool canCutToClipboard() override; virtual bool canCopyToClipboard() override; virtual bool canPasteFromClipboard() override; QtnPropertyBase *getActiveProperty() const; static void addShortcutForAction(const QKeySequence &seq, QAction *action, QWidget *parent, Qt::ShortcutContext shortcutContext = Qt::WidgetWithChildrenShortcut); private: void onMouseReleased(); void onResetTriggered(); void onLockToggleTriggered(); public slots: void deleteActiveProperty(); void cutToClipboard(); void copyToClipboard(); void pasteFromClipboard(); protected: virtual void contextMenuEvent(QContextMenuEvent *event) override; virtual bool dataHasSupportedFormats(const QMimeData *data) override; virtual void deleteProperty(QtnPropertyBase *property) override; virtual QMimeData *getPropertyDataForAction( QtnPropertyBase *property, Qt::DropAction dropAction) override; virtual bool applyPropertyData(const QMimeData *data, QtnPropertyBase *destination, QtnApplyPosition position) override; virtual bool eventFilter(QObject *obj, QEvent *event) override; virtual void dragEnterEvent(QDragEnterEvent *event) override; virtual void dragMoveEvent(QDragMoveEvent *event) override; virtual void dropEvent(QDropEvent *event) override; virtual bool drop(const QMimeData *data, QtnPropertyBase *property, QtnApplyPosition applyPosition); virtual void dropEnd(); private: void onDropFinished(Qt::DropAction action); bool dragAndDrop(); void internalConnect( QAction *dropAction, void (QtnPropertyWidgetEx::*slot)(), bool connect); QPoint dragStartPos; QtnPropertyBase *draggedProperty; QDrag *mDrag; Qt::DropAction dropAction; bool canRemove; }; ================================================ FILE: QtnProperty/QObjectPropertySet.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "QObjectPropertySet.h" #include "PropertyCore.h" #include "PropertyGUI.h" #include "PropertyConnector.h" #include "MultiProperty.h" #include "IQtnPropertyStateProvider.h" #include "Install.h" #include "PropertyDelegateAttrs.h" #include #include #include #include #include static QMap &qtnFactoryMap() { static QMap result; return result; }; bool qtnRegisterMetaPropertyFactory( int metaPropertyType, const QtnMetaPropertyFactory_t &factory, bool force) { Q_ASSERT(factory); auto &map = qtnFactoryMap(); if (!force && map.contains(metaPropertyType)) return false; map.insert(metaPropertyType, factory); return true; } QtnPropertyState qtnPropertyStateToAdd(const QMetaProperty &metaProperty) { QtnPropertyState toAdd; if (!metaProperty.isDesignable()) toAdd |= QtnPropertyStateInvisible; if (metaProperty.isConstant() || (!metaProperty.isWritable() && !metaProperty.isResettable())) { toAdd |= QtnPropertyStateImmutable; } return toAdd; } void qtnUpdatePropertyState( QtnPropertyBase *property, const QMetaProperty &metaProperty) { property->addState(qtnPropertyStateToAdd(metaProperty)); } QtnProperty *qtnCreateQObjectProperty(QObject *object, const QMetaProperty &metaProperty, bool connect, const char *className) { if (!object) return nullptr; auto &map = qtnFactoryMap(); auto it = map.find(metaProperty.type()); if (it == map.end()) it = map.find(metaProperty.userType()); if (it == map.end()) return nullptr; if (!metaProperty.isDesignable(object) || !metaProperty.isReadable()) return nullptr; QtnProperty *property = it.value()(object, metaProperty); if (!property) return property; property->setName(metaProperty.name()); if (className) { property->setDisplayName( QCoreApplication::translate(className, metaProperty.name())); } auto stateProvider = dynamic_cast(object); if (nullptr != stateProvider) { auto state = stateProvider->getPropertyState(metaProperty); property->setState(state); } qtnUpdatePropertyState(property, metaProperty); if (connect) { auto connector = new QtnPropertyConnector(property); connector->connectProperty(object, metaProperty); } return property; } QtnProperty *qtnCreateQObjectProperty( QObject *object, const char *propertyName, bool connect) { if (!object) return nullptr; const QMetaObject *metaObject = object->metaObject(); int propertyIndex = -1; while (metaObject) { propertyIndex = object->metaObject()->indexOfProperty(propertyName); if (propertyIndex != -1) break; metaObject = metaObject->superClass(); } if (!metaObject) return nullptr; if (propertyIndex == -1) return nullptr; Q_ASSERT(propertyIndex >= 0 && propertyIndex < metaObject->propertyCount()); return qtnCreateQObjectProperty(object, metaObject->property(propertyIndex), connect, metaObject->className()); } QtnPropertySet *qtnCreateQObjectPropertySet(QObject *object, bool backwards) { if (!object) return nullptr; // collect property sets by object's classes QStringList classNames; std::map propertySetsByClass; auto metaObject = object->metaObject(); while (nullptr != metaObject) { if (metaObject->propertyCount() > 0) { QList properties; for (int propertyIndex = metaObject->propertyOffset(), n = metaObject->propertyCount(); propertyIndex < n; ++propertyIndex) { auto metaProperty = metaObject->property(propertyIndex); auto property = qtnCreateQObjectProperty( object, metaProperty, true, metaObject->className()); if (nullptr != property) properties.append(property); } if (!properties.isEmpty()) { auto className = QCoreApplication::translate( "ClassName", metaObject->className()); auto it = propertySetsByClass.find(className); QtnPropertySet *propertySetByClass; if (it != propertySetsByClass.end()) { propertySetByClass = it->second; } else { propertySetByClass = new QtnPropertySet; propertySetByClass->setName(className); propertySetsByClass[className] = propertySetByClass; classNames.push_back(className); } for (auto property : properties) { propertySetByClass->addChildProperty(property); } } } // move up in class hierarchy metaObject = metaObject->superClass(); } if (propertySetsByClass.empty()) return nullptr; // move collected property sets to object's property set auto propertySet = new QtnPropertySet; propertySet->setName(object->objectName()); int addIndex = backwards ? 0 : -1; for (auto &class_name : classNames) { propertySet->addChildProperty( propertySetsByClass[class_name], true, addIndex); } return propertySet; } QtnPropertySet *qtnCreateQObjectMultiPropertySet( const std::set &objects, bool backwards) { if (objects.empty()) return nullptr; auto result = new QtnPropertySet(nullptr); for (auto object : objects) { auto propertySet = qtnCreateQObjectPropertySet(object, backwards); if (nullptr == propertySet) continue; qtnPropertiesToMultiSet(result, propertySet, true); delete propertySet; } return result; } ================================================ FILE: QtnProperty/QObjectPropertySet.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_QOBJECT_PROPERTY_SET_H #define QTN_QOBJECT_PROPERTY_SET_H #include "Config.h" #include "Auxiliary/PropertyAux.h" #include #include #include #include class QtnPropertyBase; class QtnProperty; class QtnPropertySet; struct QtnPropertyDelegateInfo; typedef std::function QtnMetaPropertyFactory_t; QTN_IMPORT_EXPORT bool qtnRegisterMetaPropertyFactory(int metaPropertyType, const QtnMetaPropertyFactory_t &factory, bool force = false); QTN_IMPORT_EXPORT QtnProperty *qtnCreateQObjectProperty(QObject *object, const QMetaProperty &metaProperty, bool connect = false, const char *className = nullptr); QTN_IMPORT_EXPORT QtnProperty *qtnCreateQObjectProperty( QObject *object, const char *propertyName, bool connect = false); QTN_IMPORT_EXPORT QtnPropertySet *qtnCreateQObjectPropertySet( QObject *object, bool backwards = false); QTN_IMPORT_EXPORT QtnPropertySet *qtnCreateQObjectMultiPropertySet( const std::set &objects, bool backwards); QTN_IMPORT_EXPORT QtnPropertyState qtnPropertyStateToAdd( const QMetaProperty &metaProperty); QTN_IMPORT_EXPORT void qtnUpdatePropertyState( QtnPropertyBase *property, const QMetaProperty &metaProperty); template QtnMetaPropertyFactory_t qtnCreateFactory() { using CallbackValueType = typename PropertyCallbackType::ValueType; using CallbackValueTypeStore = typename PropertyCallbackType::ValueTypeStore; auto result = [](QObject *object, const QMetaProperty &metaProperty) -> QtnProperty * { auto property = new PropertyCallbackType(nullptr); property->setCallbackValueGet( [object, metaProperty]() -> CallbackValueTypeStore { auto variantValue = metaProperty.read(object); return CallbackValueTypeStore(variantValue.value()); }); property->setCallbackValueSet( [object, metaProperty](CallbackValueType value, QtnPropertyChangeReason /*reason*/) { auto variantValue = QVariant::fromValue(ValueType(value)); metaProperty.write(object, variantValue); }); return property; }; return result; } #endif // QTN_QOBJECT_PROPERTY_SET_H ================================================ FILE: QtnProperty/QObjectPropertyWidget.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "QObjectPropertyWidget.h" #include "QObjectPropertySet.h" #include "PropertyConnector.h" #include "MultiProperty.h" #include "Utils/QtnConnections.h" #include "PropertySet.h" QObjectPropertyWidget::QObjectPropertyWidget(QWidget *parent) : QtnPropertyWidgetEx(parent) , mListInheritanceBackwards(true) { } void QObjectPropertyWidget::setListInheritanceBackwards(bool value) { if (mListInheritanceBackwards == value) { return; } disconnectObjects(); mListInheritanceBackwards = value; connectObjects(); } void QObjectPropertyWidget::deselectAllObjects() { disconnectObjects(); selectedObjects.clear(); } void QObjectPropertyWidget::selectObject(QObject *object, bool addSelection) { auto it = selectedObjects.find(object); if (it == selectedObjects.end() || (!addSelection && selectedObjects.size() > 1)) { if (addSelection) disconnectObjects(); else deselectAllObjects(); selectedObjects.insert(object); connectObjects(); } } void QObjectPropertyWidget::selectObjects( const Objects &objects, bool addSelection) { if (objects != selectedObjects) { if (addSelection) { disconnectObjects(); selectedObjects.insert(objects.begin(), objects.end()); } else { deselectAllObjects(); selectedObjects = objects; } connectObjects(); } } void QObjectPropertyWidget::deselectObject(QObject *object, bool destroyed) { if (destroyed) onObjectDestroyed(object); else { auto it = selectedObjects.find(object); if (it != selectedObjects.end()) { disconnectObjects(); selectedObjects.erase(it); connectObjects(); } } } void QObjectPropertyWidget::onObjectDestroyed(QObject *object) { auto it = selectedObjects.find(object); if (it != selectedObjects.end()) { selectedObjects.erase(it); disconnectObjects(); connectObjects(); } } QtnMultiProperty *QObjectPropertyWidget::getMultiProperty() const { return dynamic_cast(getActiveProperty()); } QtnPropertyConnector *QObjectPropertyWidget::getPropertyConnector() const { auto property = getActiveProperty(); if (nullptr != property) { return property->getConnector(); } return nullptr; } void QObjectPropertyWidget::connectObjects() { if (selectedObjects.size() == 1) { auto object = *selectedObjects.begin(); auto set = qtnCreateQObjectPropertySet(object, mListInheritanceBackwards); if (nullptr != set) set->setParent(this); setPropertySet(set); connectObject(object); } else if (selectedObjects.size() > 1) { auto set = qtnCreateQObjectMultiPropertySet( selectedObjects, mListInheritanceBackwards); if (nullptr != set) set->setParent(this); setPropertySet(set); for (auto object : selectedObjects) { connectObject(object); } } } void QObjectPropertyWidget::connectObject(QObject *object) { Q_ASSERT(nullptr != object); QObject::connect(object, &QObject::destroyed, this, &QObjectPropertyWidget::onObjectDestroyed); } void QObjectPropertyWidget::disconnectObjects() { auto set = propertySet(); setPropertySet(nullptr); delete set; for (auto object : selectedObjects) { disconnectObject(object); } } void QObjectPropertyWidget::disconnectObject(QObject *object) { Q_ASSERT(nullptr != object); QObject::disconnect(object, &QObject::destroyed, this, &QObjectPropertyWidget::onObjectDestroyed); } ================================================ FILE: QtnProperty/QObjectPropertyWidget.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "PropertyWidgetEx.h" #include #include class QtnPropertyConnector; class QtnMultiProperty; class QTN_IMPORT_EXPORT QObjectPropertyWidget : public QtnPropertyWidgetEx { Q_OBJECT public: explicit QObjectPropertyWidget(QWidget *parent = nullptr); typedef std::set Objects; inline const Objects &getSelectedObjects() const; bool isListInheritanceBackwards() const; void setListInheritanceBackwards(bool value); public slots: void deselectAllObjects(); void selectObject(QObject *object, bool addSelection = true); void selectObjects(const Objects &objects, bool addSelection = true); void deselectObject(QObject *object, bool destroyed = false); private: void onObjectDestroyed(QObject *object); protected: QtnMultiProperty *getMultiProperty() const; QtnPropertyConnector *getPropertyConnector() const; void connectObjects(); void disconnectObjects(); void disconnectObject(QObject *object); void connectObject(QObject *object); Objects selectedObjects; bool mListInheritanceBackwards; }; const QObjectPropertyWidget::Objects & // QObjectPropertyWidget::getSelectedObjects() const { return selectedObjects; } inline bool QObjectPropertyWidget::isListInheritanceBackwards() const { return mListInheritanceBackwards; } ================================================ FILE: QtnProperty/QtnProperty.pri ================================================ QT += core gui widgets script SOURCES +=\ $$PWD/PropertyBase.cpp \ $$PWD/Property.cpp \ $$PWD/PropertySet.cpp \ $$PWD/Enum.cpp \ $$PWD/QObjectPropertySet.cpp \ $$PWD/Core/PropertyBool.cpp \ $$PWD/Core/PropertyInt.cpp \ $$PWD/Core/PropertyUInt.cpp \ $$PWD/Core/PropertyDouble.cpp \ $$PWD/Core/PropertyFloat.cpp \ $$PWD/Core/PropertyQString.cpp \ $$PWD/Core/PropertyQRect.cpp \ $$PWD/Core/PropertyEnum.cpp \ $$PWD/Core/PropertyEnumFlags.cpp \ $$PWD/Core/PropertyQSize.cpp \ $$PWD/Core/PropertyQPoint.cpp \ $$PWD/GUI/PropertyQColor.cpp \ $$PWD/GUI/PropertyQFont.cpp \ $$PWD/GUI/PropertyQBrush.cpp \ $$PWD/GUI/PropertyQPen.cpp \ $$PWD/GUI/PropertyButton.cpp \ $$PWD/PropertyWidget.cpp \ $$PWD/PropertyView.cpp \ $$PWD/Utils/InplaceEditing.cpp \ $$PWD/Delegates/PropertyDelegate.cpp \ $$PWD/Delegates/PropertyDelegateAux.cpp \ $$PWD/Delegates/PropertyDelegateFactory.cpp \ $$PWD/Delegates/Core/PropertyDelegateBool.cpp \ $$PWD/Delegates/Core/PropertyDelegateInt.cpp \ $$PWD/Delegates/Core/PropertyDelegateUInt.cpp \ $$PWD/Delegates/Core/PropertyDelegateQString.cpp \ $$PWD/Delegates/Core/PropertyDelegateDouble.cpp \ $$PWD/Delegates/Core/PropertyDelegateFloat.cpp \ $$PWD/Delegates/Core/PropertyDelegateEnum.cpp \ $$PWD/Delegates/Core/PropertyDelegateQRect.cpp \ $$PWD/Delegates/Core/PropertyDelegateQRectF.cpp \ $$PWD/Delegates/Core/PropertyDelegateEnumFlags.cpp \ $$PWD/Delegates/Core/PropertyDelegateQSize.cpp \ $$PWD/Delegates/Core/PropertyDelegateQSizeF.cpp \ $$PWD/Delegates/Core/PropertyDelegateQPoint.cpp \ $$PWD/Delegates/Core/PropertyDelegateQPointF.cpp \ $$PWD/Delegates/GUI/PropertyDelegateQColor.cpp \ $$PWD/Delegates/GUI/PropertyDelegateQBrush.cpp \ $$PWD/Delegates/GUI/PropertyDelegateQPen.cpp \ $$PWD/Delegates/GUI/PropertyDelegateQFont.cpp \ $$PWD/Delegates/GUI/PropertyDelegateButton.cpp \ $$PWD/Delegates/Utils/PropertyEditorHandler.cpp \ $$PWD/Delegates/Utils/PropertyEditorAux.cpp \ $$PWD/Delegates/Utils/PropertyDelegateMisc.cpp \ $$PWD/Delegates/Utils/PropertyDelegatePropertySet.cpp \ $$PWD/Delegates/Utils/PropertyDelegateSliderBox.cpp \ $$PWD/Delegates/Utils/PropertyDelegateGeoCoord.cpp \ $$PWD/Delegates/Utils/PropertyDelegateGeoPoint.cpp \ $$PWD/Utils/AccessibilityProxy.cpp \ $$PWD/Utils/DoubleSpinBox.cpp \ $$PWD/Utils/MultilineTextDialog.cpp \ $$PWD/PropertyInt64.cpp \ $$PWD/PropertyUInt64.cpp \ $$PWD/Core/PropertyQRectF.cpp \ $$PWD/Core/PropertyQPointF.cpp \ $$PWD/Core/PropertyQSizeF.cpp \ $$PWD/PropertyWidgetEx.cpp \ $$PWD/CustomPropertyEditorDialog.cpp \ $$PWD/CustomPropertyOptionsDialog.cpp \ $$PWD/VarProperty.cpp \ $$PWD/PropertyQVariant.cpp \ $$PWD/CustomPropertyWidget.cpp \ $$PWD/QObjectPropertyWidget.cpp \ $$PWD/MultiProperty.cpp \ $$PWD/PropertyConnector.cpp \ $$PWD/Utils/QtnConnections.cpp \ $$PWD/Utils/QtnInt64SpinBox.cpp \ $$PWD/Auxiliary/PropertyDelegateInfo.cpp \ $$PWD/PropertyQKeySequence.cpp \ $$PWD/PropertyDelegateMetaEnum.cpp \ $$PWD/Install.cpp \ $$PWD/Utils/QtnCompleterLineEdit.cpp \ $$PWD/Utils/QtnCompleterItemDelegate.cpp \ $$PWD/GUI/PropertyQVector3D.cpp \ $$PWD/Delegates/GUI/PropertyDelegateQVector3D.cpp HEADERS +=\ $$PWD/PropertyBase.h \ $$PWD/Property.h\ $$PWD/PropertySet.h\ $$PWD/Enum.h\ $$PWD/QObjectPropertySet.h \ $$PWD/PropertyCore.h \ $$PWD/PropertyGUI.h \ $$PWD/Auxiliary/PropertyTemplates.h \ $$PWD/Auxiliary/PropertyMacro.h \ $$PWD/Auxiliary/PropertyAux.h \ $$PWD/Auxiliary/PropertyDelegateInfo.h \ $$PWD/Core/PropertyBool.h \ $$PWD/Core/PropertyInt.h \ $$PWD/Core/PropertyUInt.h \ $$PWD/Core/PropertyDouble.h \ $$PWD/Core/PropertyFloat.h \ $$PWD/Core/PropertyQString.h \ $$PWD/Core/PropertyQRect.h \ $$PWD/Core/PropertyEnum.h \ $$PWD/Core/PropertyEnumFlags.h \ $$PWD/Core/PropertyQSize.h \ $$PWD/Core/PropertyQPoint.h \ $$PWD/GUI/PropertyQColor.h \ $$PWD/GUI/PropertyQFont.h \ $$PWD/GUI/PropertyQBrush.h \ $$PWD/GUI/PropertyQPen.h \ $$PWD/GUI/PropertyButton.h \ $$PWD/PropertyWidget.h \ $$PWD/PropertyView.h \ $$PWD/Utils/InplaceEditing.h \ $$PWD/Delegates/PropertyDelegate.h \ $$PWD/Delegates/PropertyDelegateAux.h \ $$PWD/Delegates/PropertyDelegateFactory.h \ $$PWD/Delegates/Core/PropertyDelegateBool.h \ $$PWD/Delegates/Core/PropertyDelegateInt.h \ $$PWD/Delegates/Core/PropertyDelegateUInt.h \ $$PWD/Delegates/Core/PropertyDelegateQString.h \ $$PWD/Delegates/Core/PropertyDelegateDouble.h \ $$PWD/Delegates/Core/PropertyDelegateFloat.h \ $$PWD/Delegates/Core/PropertyDelegateEnum.h \ $$PWD/Delegates/Core/PropertyDelegateQRect.h \ $$PWD/Delegates/Core/PropertyDelegateQRectF.h \ $$PWD/Delegates/Core/PropertyDelegateEnumFlags.h \ $$PWD/Delegates/Core/PropertyDelegateQSize.h \ $$PWD/Delegates/Core/PropertyDelegateQSizeF.h \ $$PWD/Delegates/Core/PropertyDelegateQPoint.h \ $$PWD/Delegates/Core/PropertyDelegateQPointF.h \ $$PWD/Delegates/GUI/PropertyDelegateQColor.h \ $$PWD/Delegates/GUI/PropertyDelegateQFont.h \ $$PWD/Delegates/GUI/PropertyDelegateQBrush.h \ $$PWD/Delegates/GUI/PropertyDelegateQPen.h \ $$PWD/Delegates/GUI/PropertyDelegateButton.h \ $$PWD/Delegates/Utils/PropertyEditorHandler.h \ $$PWD/Delegates/Utils/PropertyEditorAux.h \ $$PWD/Delegates/Utils/PropertyDelegateMisc.h \ $$PWD/Delegates/Utils/PropertyDelegatePropertySet.h \ $$PWD/Delegates/Utils/PropertyDelegateSliderBox.h \ $$PWD/Delegates/Utils/PropertyDelegateGeoCoord.h \ $$PWD/Delegates/Utils/PropertyDelegateGeoPoint.h \ $$PWD/Utils/AccessibilityProxy.h \ $$PWD/Utils/DoubleSpinBox.h \ $$PWD/Utils/MultilineTextDialog.h \ $$PWD/PropertyInt64.h \ $$PWD/PropertyUInt64.h \ $$PWD/Core/PropertyQRectF.h \ $$PWD/Core/PropertyQPointF.h \ $$PWD/Core/PropertyQSizeF.h \ $$PWD/PropertyWidgetEx.h \ $$PWD/CustomPropertyEditorDialog.h \ $$PWD/CustomPropertyOptionsDialog.h \ $$PWD/VarProperty.h \ $$PWD/PropertyQVariant.h \ $$PWD/CustomPropertyWidget.h \ $$PWD/QObjectPropertyWidget.h \ $$PWD/IQtnPropertyStateProvider.h \ $$PWD/MultiProperty.h \ $$PWD/StructPropertyBase.h \ $$PWD/PropertyConnector.h \ $$PWD/Utils/QtnConnections.h \ $$PWD/Utils/QtnInt64SpinBox.h \ $$PWD/PropertyDelegateAttrs.h \ $$PWD/PropertyQKeySequence.h \ $$PWD/PropertyDelegateMetaEnum.h \ $$PWD/Install.h \ $$PWD/Config.h \ $$PWD/FunctionalHelpers.h \ $$PWD/Utils/QtnCompleterLineEdit.h \ $$PWD/Utils/QtnCompleterItemDelegate.h \ $$PWD/GUI/PropertyQVector3D.h \ $$PWD/Delegates/GUI/PropertyDelegateQVector3D.h TRANSLATIONS += \ $$PWD/Translations/en.ts \ $$PWD/Translations/ru.ts for(tr, TRANSLATIONS):system($$[QT_INSTALL_BINS]/lrelease $${tr}) RESOURCES += $$PWD/QtnProperty.qrc FORMS += \ $$PWD/CustomPropertyEditorDialog.ui \ $$PWD/CustomPropertyOptionsDialog.ui \ $$PWD/Utils/MultilineTextDialog.ui INCLUDEPATH += $$PWD/.. ================================================ FILE: QtnProperty/QtnProperty.pro ================================================ include(../Internal/TargetConfig.pri) TARGET = QtnProperty TEMPLATE = lib VERSION = 2.0.3 qtnproperty_dynamic { DEFINES += QTN_DYNAMIC_LIBRARY macx { QMAKE_SONAME_PREFIX = @rpath } CONFIG += shared } else { CONFIG += static } include(./QtnProperty.pri) ================================================ FILE: QtnProperty/QtnProperty.qrc ================================================ Translations/en.qm Translations/ru.qm ================================================ FILE: QtnProperty/StructPropertyBase.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "Auxiliary/PropertyTemplates.h" template void qtnSetFieldValue(CLASS_T &to, SETTER_T setter, FIELD_T value, typename std::enable_if< std::is_member_function_pointer::value>::type * = nullptr) { (to.*setter)(value); } template void qtnSetFieldValue(CLASS_T &to, SETTER_T field, FIELD_T value, typename std::enable_if< std::is_member_object_pointer::value>::type * = nullptr) { to.*field = value; } template FIELD_T qtnGetFieldValue(CLASS_T from, GETTER_T getter, typename std::enable_if< std::is_member_function_pointer::value>::type * = nullptr) { return (from.*getter)(); } template FIELD_T qtnGetFieldValue(const CLASS_T &from, GETTER_T field, typename std::enable_if< std::is_member_object_pointer::value>::type * = nullptr) { return from.*field; } template FIELD_PROP_T *qtnCreateFieldProperty(QtnSinglePropertyBase *property, GETTER_T getter, SETTER_T setter, const QString &name = QString(), const QString &displayName = QString(), const QString &desc_fmt = QString()) { using CallbackValueType = typename FIELD_PROP_T::ValueType; using CallbackValueTypeStore = typename FIELD_PROP_T::ValueTypeStore; using ValueTypeStore = typename QtnSinglePropertyBase::ValueTypeStore; Q_ASSERT(property); auto result = new FIELD_PROP_T(nullptr); if (!displayName.isEmpty()) result->setDisplayName(displayName); if (!name.isEmpty()) result->setName(name); if (!desc_fmt.isEmpty()) result->setDescription(desc_fmt.arg(property->displayName())); result->setCallbackValueGet([property, getter]() -> CallbackValueTypeStore { return qtnGetFieldValue( property->value(), getter); }); result->setCallbackValueSet( [property, setter](CallbackValueType new_value, QtnPropertyChangeReason reason) { auto v = property->value(); qtnSetFieldValue(v, setter, new_value); property->setValue(v, reason); }); if (!property->isQObjectProperty() && property->isResettable()) { result->addState(QtnPropertyStateResettable); result->setCallbackValueDefault( [property, getter]() -> CallbackValueTypeStore { ValueTypeStore value; if (!property->readDefaultValue(value)) { value = property->value(); } return qtnGetFieldValue(value, getter); }); } auto delegateInfoCallback = [property]() -> QtnPropertyDelegateInfo { auto baseDelegate = property->delegateInfo(); QtnPropertyDelegateInfo result; if (baseDelegate) { result.attributes = baseDelegate->attributes; auto it = result.attributes.find(qtnFieldDelegateNameAttr()); if (it != result.attributes.end()) { result.name = it.value().toByteArray(); } } return result; }; result->setDelegateInfoCallback(delegateInfoCallback); return result; } template class QtnStructPropertyBase : public QtnSinglePropertyBase { typedef QtnSinglePropertyBase Inherited; public: typedef QtnStructPropertyBase ParentClass; template inline FIELD_PROP_T *createFieldProperty(GETTER_T getter, SETTER_T setter, const QString &name = QString(), const QString &displayName = QString(), const QString &desc_fmt = QString()) { return qtnCreateFieldProperty( this, getter, setter, name, displayName, desc_fmt); } protected: explicit QtnStructPropertyBase(QObject *parent) : Inherited(parent) { } }; ================================================ FILE: QtnProperty/Translations/en.ts ================================================ BasePropertyDialog Property with name '%1' is already exist. Property with name "%1" is already exist. CustomPropertyEditorDialog Custom Property Editor Custom Property Editor Do you want to insert new property from clipboard? If you press 'No', selected property will be replaced. Do you want to insert new property from clipboard? If you press 'No', selected property will be replaced. Add Element Add Element Duplicate Element Duplicate Element Element Options Element Options Add... Add... Add Property... Add Property... Add Element... Add Element... New... New... New Property... New Property... New Element... New Element... Edit Custom Properties Edit Custom Properties Read-only Properties Read-only Properties Add Child Property... Add Child Property... Add Child Property Add Child Property Remove Remove Delete Delete Duplicate... Duplicate... Options... Options... Cut Cut Copy Copy Paste Paste Remove Property Remove Property Duplicate Property Duplicate Property Property Options Property Options Add Property Add Property CustomPropertyOptionsDialog Name: Name: Type Type Numeric Numeric String String Boolean Boolean Dictionary Dictionary List List Null Null Index: Index: CustomPropertyWidget Add Element Add Element Add Property Add Property New Element New Element New Property New Property Duplicate Element Duplicate Element Duplicate Property Duplicate Property Property Options Property Options Element Options Element Options Do you want to insert new property from clipboard or to replace the selected one? Do you want to insert new property from clipboard or to replace the selected one? Insert Paste Insert Replace Paste Replace Do you want to insert new property from clipboard? If you press 'No', selected property will be replaced. Do you want to insert new property from clipboard? If you press 'No', selected property will be replaced. QObjectPropertyWidget Reset to default Reset to default Reset value of %1 to default Reset value of %1 to default Qt NoPen Nothing SolidLine Solid Line DashLine Dash Line DotLine Dot Line DashDotLine Dash-Dot Line DashDotDotLine Dash-Dot-Dot Line CustomDashLine Custom Dash Line FlatCap Flat Cap SquareCap Square Cap RoundCap Round Cap MiterJoin Miter Join BevelJoin Bevel Join RoundJoin Round Join SvgMiterJoin SVG Miter Join QtnCustomPropertyWidget New Element New Element New Property New Property Duplicate Element Duplicate Element Duplicate Property Duplicate Property Property Options Property Options Element Options Element Options Do you want to insert new property from clipboard or to replace the selected one? Do you want to insert new property from clipboard or to replace the selected one? Insert Paste Insert Replace Paste Replace QtnMultiProperty (Multiple Values) (Multiple Values) QtnPropertyBool True True False False QtnPropertyEnumFlags %1 flag for %2 %1 flag for %2 QtnPropertyQBrushStyle NoBrush Nothing Solid Solid Dense1Pattern Dense1 Pattern Dense2Pattern Dense 2 Pattern Dense3Pattern Dense 3 Pattern Dense4Pattern Dense 4 Pattern Dense5Pattern Dense 5 Pattern Dense6Pattern Dense 6 Pattern Dense7Pattern Dense 7 Pattern HorPattern Horizontal Pattern VerPattern Vertical Pattern CrossPattern Cross Pattern BDiagPattern Backward Diagonal Pattern FDiagPattern Forward Diagonal Pattern DiagCrossPattern Diagonal Cross Pattern LinearGradientPattern Linear Gradient Pattern RadialGradientPattern Radial Gradient Pattern ConicalGradientPattern Conical Gradient Pattern TexturePattern Texture Pattern QtnPropertyQColor Red Red Red component of %1 Red component of %1 Green Green Green component of %1 Green component of %1 Blue Blue Blue component of %1 Blue component of %1 QtnPropertyQFont PreferDefault Default NoAntialias Disabled PreferAntialias Enabled Family Family Font Family for %1 Font Family for %1 PointSize Point size Point size for %1 Point size for %1 Pixels Pixels Points Points Family for %1 Font Family for %1 Size Size Size for %1 Size for %1 Size Units Size Units Size units for %1 Size units for %1 Pixel Pixel Point Point Style Style Style for %1 Style for %1 Size Unit Size Unit Size Unit for %1 Size Unit for %1 Bold Bold Bold flag for %1 Bold flag for %1 Italic Italic Italic flag for %1 Italic flag for %1 Underline Underline Underline flag for %1 Underline flag for %1 Strikeout Strikeout Strikeout flag for %1 Strikeout flag for %1 Kerning Kerning Kerning flag for %1 Kerning flag %1 Antialiasing Antialiasing Antialiasing options for %1 Antialiasing options for %1 Antialiasing flag for %1 Antialiasing flag for %1 QtnPropertyQPen (Pen) (Pen) Color Color Color of the %1 Color of the %1 Style Style Style of the %1 Style of the %1 Cap Style Cap Style Cap Style of the %1 Cap Style of the %1 Join Style Join Style Join Style of the %1 Join Style of the %1 QtnPropertyQPoint X X X of the %1 X of the %1 Y of the %1 Y of the %1 X coordinate of the %1 X coordinate of the %1 Y Y Y coordinate of the %1 Y coordinate of the %1 [%1, %2] [%1, %2] %1, %2 %1, %2 QtnPropertyQPointF X X X of the %1 X of the %1 Y Y Y of the %1 Y of the %1 QtnPropertyQRect Left Left Left side of the %1 Left offset of the %1 Right Right Right side of the %1 Right offset of the %1 Top Top Top of the %1 Top offset of the %1 Bottom Bottom Bottom of the %1 Bottom offset of the %1 Width Width Width of the %1 Width of the %1 Height Height Height of the %1 Height of the %1 [(%1, %2), (%3, %4)] [(%1, %2), (%3, %4)] [(%1, %2) %3 x %4] [(%1, %2) %3 x %4] Left position of the %1 Left position of the %1 Top position of the %1 Top position of the %1 Right position of the %1 Right position of the %1 Bottom position of the %1 Bottom position of the %1 (%1, %2) %3 x %4 (%1, %2) %3 x %4 (%1, %2), (%3, %4) (%1, %2), (%3, %4) (%1, %2), %3 x %4 (%1, %2), %3 x %4 QtnPropertyQRectF Left Left Left position of the %1 Left position of the %1 Top Top Top position of the %1 Top position of the %1 Right Right Right position of the %1 Right position of the %1 Bottom Bottom Bottom position of the %1 Bottom position of the %1 Width Width Width of the %1 Width of the %1 Height Height Height of the %1 Height of the %1 QtnPropertyQSize Width Width Width of the %1 Width of the %1 Height Height Height of the %1 Height of the %1 [%1 x %2] [%1 x %2] %1 x %2 %1 x %2 QtnPropertyQSizeF Width Width Width of the %1 Width of the %1 Height Height Height of the %1 Height of the %1 QtnPropertyQString (Multiline Text) (Multiline Text) (Empty) (Empty) %1 (Read only) %1 (Read only) QtnPropertyQVariant (Dictionary) (Dictionary) (List) (List) (Empty) (Empty) QtnPropertyQVector3D Z Z Z of the %1 Z of the %1 [%1, %2, %3] [%1, %2, %3] QtnPropertyView Lock 📕Lock Unlock 📖Unlock Click to expand Click to expand Click to collapse Click to collapse Reset to default value Reset to default value R Reset button text R Drag/Scroll mouse to change value Drag/Scroll mouse to change value QtnPropertyWidgetEx Reset to default Reset to default value Reset value of %1 to default Reset value of %1 to default Unlock property 📖Unlock property Lock property 📕Lock property Unlock %1 Unlock %1 Lock %1 Lock %1 ================================================ FILE: QtnProperty/Translations/ru.ts ================================================ BasePropertyDialog Property with name '%1' is already exist. Свойство с именем "%1" уже существует. CustomPropertyEditorDialog Custom Property Editor Настраиваемые свойства Do you want to insert new property from clipboard? If you press 'No', selected property will be replaced. Хотите вставить новое свойство из буфера обмена? Если вы нажмёте "Нет", то выбранное свойство будет заменено. Add Element Добавить элемент Duplicate Element Дублировать элемент Element Options Настройки элемента Add... Добавить... Add Property... Добавить свойство... Add Element... Добавить элемент... New... Создать... New Property... Новое свойство... New Element... Новый элемент... Edit Custom Properties Редактировать свойства Read-only Properties Свойства только для чтения Add Child Property... Добавить свойство... Add Child Property Добавить свойство Remove Удалить Delete Удалить Duplicate... Дублировать... Options... Настройки... Cut Вырезать Copy Копировать Paste Вставить Remove Property Удалить свойство Duplicate Property Дублировать свойство Property Options Настройки свойства Add Property Добавить свойство CustomPropertyOptionsDialog Name: Название: Type Тип Numeric Числовой String Строковый Boolean Логический Dictionary Словарь List Список Null Пусто Index: Индекс: CustomPropertyWidget Add Element Добавить элемент Add Property Добавить свойство New Element Новый элемент New Property Новое свойство Duplicate Element Дублировать элемент Duplicate Property Дублировать свойство Property Options Настройки свойства Element Options Настройки элемента Do you want to insert new property from clipboard or to replace the selected one? Хотите вставить новое свойство или заменить выбранное? Insert Paste Вставить Replace Paste Заменить Do you want to insert new property from clipboard? If you press 'No', selected property will be replaced. Хотите вставить новое свойство из буфера обмена? Если вы нажмёте "Нет", то выбранное свойство будет заменено. QObjectPropertyWidget Reset to default Сбросить значение Reset value of %1 to default %1: Установить значение по умолчанию Qt NoPen Ничего SolidLine Сплошная линия DashLine Штриховой пунктир DotLine Пунктирная линия DashDotLine Смешанный пунктир DashDotDotLine Двойной смешанный пунктир CustomDashLine Настраиваемый пунктир FlatCap Плоская крышка SquareCap Квадратная крышка RoundCap Круглая крышка MiterJoin Угловое соединение BevelJoin Квадратное соединение RoundJoin Круглое соединение SvgMiterJoin Угловое соединение (SWG) QtnCustomPropertyWidget New Element Новый элемент New Property Новое свойство Duplicate Element Дублировать элемент Duplicate Property Дублировать свойство Property Options Настройки свойства Element Options Настройки элемента Do you want to insert new property from clipboard or to replace the selected one? Хотите вставить новое свойство или заменить выбранное? Insert Paste Вставить Replace Paste Заменить QtnMultiProperty (Multiple Values) (Несколько значений) QtnPropertyBool True Включено False Выключено QtnPropertyEnumFlags %1 flag for %2 %2: %1 QtnPropertyQBrushStyle NoBrush Нет Solid Сплошная заливка Dense1Pattern Плотный узор №1 Dense2Pattern Плотный узор №2 Dense3Pattern Плотный узор №3 Dense4Pattern Плотный узор №4 Dense5Pattern Плотный узор №5 Dense6Pattern Плотный узор №6 Dense7Pattern Плотный узор №7 HorPattern Горизонтальный узор VerPattern Вертикальный узор CrossPattern Узор крестиком BDiagPattern Обратно-диагональный узор FDiagPattern Прямо-диагональный узор DiagCrossPattern Узор диагональным крестиком LinearGradientPattern Линейный градиент RadialGradientPattern Радиальный градиент ConicalGradientPattern Конический градиент TexturePattern Текстура QtnPropertyQColor Red Красный Red component of %1 %1 - красный компонент Green Зелёный Green component of %1 %1 - зелёный компонент Blue Синий Blue component of %1 %1 - синий компонент QtnPropertyQFont PreferDefault По умолчанию NoAntialias Выключено PreferAntialias Включено Family Семейство Font Family for %1 %1: Семейство шрифтов PointSize Размер точки Point size for %1 %1: Размер точки Pixels Пиксели Points Точки Family for %1 %1: Семейство шрифтов Size Размер Size for %1 %1: Размер Size Units Единицы измерения Size units for %1 %1: Единицы измерения размера Pixel Пиксель Point Точка Style Стиль Style for %1 %1: Стиль Size Unit Единица измерения Size Unit for %1 %1: Единица измерения размера Bold Полужирный Bold flag for %1 %1: Будет ли текст полужирным Italic Курсив Italic flag for %1 %1: Будет ли текст курсивным Underline Подчёркнутый Underline flag for %1 %1: Будет ли текст подчёркнутым Strikeout Зачёркнутый Strikeout flag for %1 %1: Будет ли текст зачёркнутым Kerning Кернинг Kerning flag for %1 %1: Кернинг Antialiasing Сглаживание Antialiasing options for %1 %1: Опции сглаживания Antialiasing flag for %1 %1: Сглаживание QtnPropertyQPen (Pen) (Карандаш) Color Цвет Color of the %1 %1 - цвет Style Стиль Style of the %1 %1 - стиль Cap Style Стиль крышки Cap Style of the %1 %1 - стиль крышки Join Style Стиль соединения Join Style of the %1 %1 - стиль соединения QtnPropertyQPoint X X X of the %1 Координата X от "%1" Y of the %1 Координата Y от "%1" X coordinate of the %1 Координата X точки "%1" Y Y Y coordinate of the %1 Координата Y точки "%1" [%1, %2] [%1; %2] %1, %2 %1; %2 QtnPropertyQPointF X X X of the %1 Координата X точки "%1" Y Y Y of the %1 Координата Y точки "%1" QtnPropertyQRect Left Отступ слева Left side of the %1 Отступ слева для прямоугольника "%1" Right Отступ справа Right side of the %1 Отступ справа для прямоугольника "%1" Top Отступ сверху Top of the %1 Отступ сверху для прямоугольника "%1" Bottom Отступ снизу Bottom of the %1 Отступ снизу для прямоугольника "%1" Width Ширина Width of the %1 Ширина прямоугольника "%1" Height Высота Height of the %1 Высота прямоугольника "%1" [(%1, %2), (%3, %4)] [(%1; %2), (%3; %4)] [(%1, %2) %3 x %4] [(%1; %2) %3 x %4] Left position of the %1 %1: Координата X левой стороны Top position of the %1 %1: Координата Y верхней стороны Right position of the %1 %1: Координата X правой стороны Bottom position of the %1 %1: Координата Y нижней стороны (%1, %2) %3 x %4 (%1; %2) %3 x %4 (%1, %2), (%3, %4) (%1; %2), (%3; %4) (%1, %2), %3 x %4 (%1; %2), %3 x %4 QtnPropertyQRectF Left Слева Left position of the %1 %1: Координата X левой стороны Top Сверху Top position of the %1 %1: Координата Y верхней стороны Right Справа Right position of the %1 %1: Координата X правой стороны Bottom Снизу Bottom position of the %1 %1: Координата Y нижней стороны Width Ширина Width of the %1 %1: Ширина Height Высота Height of the %1 %1: Высота QtnPropertyQSize Width Ширина Width of the %1 %1: Ширина Height Высота Height of the %1 %1: Высота [%1 x %2] [%1 x %2] %1 x %2 %1 x %2 QtnPropertyQSizeF Width Ширина Width of the %1 %1: Ширина Height Высота Height of the %1 %1: Высота QtnPropertyQString (Multiline Text) (Многострочный текст) (Empty) (Пусто) %1 (Read only) %1 (Только чтение) QtnPropertyQVariant (Dictionary) (Словарь) (List) (Список) (Empty) (Пусто) QtnPropertyQVector3D Z Z Z of the %1 Координата Z от "%1" [%1, %2, %3] [%1; %2; %3] QtnPropertyView Lock 📕Заблокировать Unlock 📖Разблокировать Click to expand Щёлкните, чтобы развернуть Click to collapse Щёлкните, чтобы свернуть Reset to default value Вернуть значение по умолчанию R Reset button text С Drag/Scroll mouse to change value Меняйте значение с помощью колёсика или левой кнопки мыши QtnPropertyWidgetEx Reset to default Сбросить значение Reset value of %1 to default %1: Установить значение по умолчанию Unlock property 📖Разблокировать свойство Lock property 📕Заблокировать свойство Unlock %1 Разблокировать %1 Lock %1 Заблокировать %1 ================================================ FILE: QtnProperty/Utils/AccessibilityProxy.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "AccessibilityProxy.h" #include "QtnProperty/PropertyView.h" #include QtnAccessibilityProxy::QtnAccessibilityProxy(QtnPropertyView *owner) : QObject(owner) , m_owner(owner) { } QtnPropertyView *QtnAccessibilityProxy::owner() { return m_owner; } QtnPropertySet *QtnAccessibilityProxy::propertySet() { return m_owner->propertySet(); } QtnPropertyBase *QtnAccessibilityProxy::activeProperty() { return m_owner->activeProperty(); } QtnPropertyBase *QtnAccessibilityProxy::findProperty(QString nameOrPath) { auto root = m_owner->propertySet(); if (!root) return nullptr; auto properties = root->findChildProperties(nameOrPath); if (properties.size() != 1) return nullptr; return properties[0]; } QtnPropertyBase *QtnAccessibilityProxy::propertyUnderPoint(QPoint point) { return m_owner->visiblePropertyAtPoint(point); } void QtnAccessibilityProxy::ensureVisibleProperty(QtnPropertyBase *property) { if (!property) return; auto currentProperty = property; while (true) { QtnPropertyBase *propertyParent = qobject_cast(currentProperty->parent()); if (!propertyParent) propertyParent = currentProperty->getMasterProperty(); if (!propertyParent) break; propertyParent->removeState(QtnPropertyStateCollapsed); currentProperty = propertyParent; } m_owner->ensureVisible(property); } QRect QtnAccessibilityProxy::propertyNameRect(QtnPropertyBase *property) { if (!property) return QRect(); int index = m_owner->visibleItemIndexByProperty(property); if (index < 0) return QRect(); QRect rect = m_owner->visibleItemRect(index); rect.setRight(m_owner->splitPosition()); return rect; } QRect QtnAccessibilityProxy::propertyValueRect(QtnPropertyBase *property) { if (!property) return QRect(); int index = m_owner->visibleItemIndexByProperty(property); if (index < 0) return QRect(); QRect rect = m_owner->visibleItemRect(index); rect.setLeft(m_owner->splitPosition() + 1); return rect; } QRect QtnAccessibilityProxy::propertyActionRect( QtnPropertyBase *property, int actionIndex) { return m_owner->propertyActionRect(property, actionIndex); } QString QtnAccessibilityProxy::propertyDelegateName(QtnPropertyBase *property) { if (!property) return QString(); if (!property->delegateInfo()) return QString(""); return property->delegateInfo()->name; } ================================================ FILE: QtnProperty/Utils/AccessibilityProxy.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef QTN_ACCESSIBILITY_PROXY_H #define QTN_ACCESSIBILITY_PROXY_H #include "QtnProperty/Config.h" #include "QtnProperty/PropertySet.h" #include #include class QtnPropertyView; class QTN_IMPORT_EXPORT QtnAccessibilityProxy : public QObject { Q_OBJECT Q_DISABLE_COPY(QtnAccessibilityProxy) public: explicit QtnAccessibilityProxy(QtnPropertyView *owner = 0); public slots: QtnPropertyView *owner(); QtnPropertyBase *activeProperty(); QtnPropertySet *propertySet(); QtnPropertyBase *findProperty(QString nameOrPath); QtnPropertyBase *propertyUnderPoint(QPoint point); void ensureVisibleProperty(QtnPropertyBase *property); QRect propertyNameRect(QtnPropertyBase *property); QRect propertyValueRect(QtnPropertyBase *property); QRect propertyActionRect(QtnPropertyBase *property, int actionIndex); QString propertyDelegateName(QtnPropertyBase *property); private: QtnPropertyView *m_owner; }; Q_DECLARE_METATYPE(QtnAccessibilityProxy *) #endif // QTN_ACCESSIBILITY_PROXY_H ================================================ FILE: QtnProperty/Utils/DoubleSpinBox.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2020 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "DoubleSpinBox.h" QtnDoubleSpinBox::QtnDoubleSpinBox(QWidget *parent) : QDoubleSpinBox(parent) { } QString QtnDoubleSpinBox::textFromValue(double val) const { return valueToText(val, locale(), decimals(), isGroupSeparatorShown()); } QValidator::State QtnDoubleSpinBox::validate(QString& text, int& pos) const { for (auto& chr : text) if (chr == QLatin1Char('.') || chr == QLatin1Char(',')) chr = locale().decimalPoint(); return QDoubleSpinBox::validate(text, pos); } QString QtnDoubleSpinBox::valueToText( double value, const QLocale &locale, int decimals, bool groupSeparatorShown) { if (!qIsFinite(value)) { return locale.toString(value); } auto str = QByteArray::number(quint64(qAbs(value))); int i = str.length(); if (!str.startsWith('0')) { i++; } int maxDecimals = std::numeric_limits::digits10 - i; decimals = std::max(0, std::min(maxDecimals, decimals)); str = QByteArray::number(value, 'f', decimals); if (decimals >= 2 && decimals == maxDecimals && (str.endsWith("99") || str.endsWith("01"))) { decimals--; } auto result = locale.toString(value, 'f', decimals); auto decimalPoint = locale.decimalPoint(); auto groupSeparator = locale.groupSeparator(); if (!groupSeparatorShown) result.remove(groupSeparator); i = result.indexOf(decimalPoint); if (i >= 0) { auto zeroDigit = locale.zeroDigit(); auto begin = result.constData(); auto data = &begin[result.length() - 1]; auto decBegin = &begin[i]; while (data >= decBegin && (*data == zeroDigit || *data == decimalPoint || *data == groupSeparator)) { data--; } result.resize(int(data + 1 - begin)); } return result; } ================================================ FILE: QtnProperty/Utils/DoubleSpinBox.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include #include "QtnProperty/Config.h" class QTN_IMPORT_EXPORT QtnDoubleSpinBox : public QDoubleSpinBox { public: explicit QtnDoubleSpinBox(QWidget *parent = nullptr); virtual QString textFromValue(double val) const override; virtual QValidator::State validate(QString &text, int &pos) const override; static QString valueToText(double value, const QLocale &locale = QLocale(), int decimals = 15, bool groupSeparatorShown = false); }; ================================================ FILE: QtnProperty/Utils/InplaceEditing.cpp ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "InplaceEditing.h" #include #include #include class QtnInplaceEditorHandler : public QObject { public: bool eventFilter(QObject *watched, QEvent *event) override; void OnEditorDestroyed(QObject *obj); }; static unsigned g_inplaceEditorRetainCount = 0; static QWidget *g_inplaceEditor = 0; static QtnInplaceEditorHandler *g_inplaceEditorHandler = 0; bool qtnStartInplaceEdit(QWidget *editor) { if (!editor) return false; Q_ASSERT(g_inplaceEditorRetainCount == 0); if (g_inplaceEditor) { qtnStopInplaceEdit(false); } Q_ASSERT(QCoreApplication::instance()); if (editor->objectName().isEmpty()) editor->setObjectName("QtnPropertyValueEditor"); if (!editor->isVisible()) editor->show(); g_inplaceEditor = editor; g_inplaceEditorHandler = new QtnInplaceEditorHandler(); // move focus to editor if (QApplication::focusWidget() != g_inplaceEditor->focusWidget()) g_inplaceEditor->setFocus(); // connect to editor destroyed signal QObject::connect(g_inplaceEditor, &QObject::destroyed, g_inplaceEditorHandler, &QtnInplaceEditorHandler::OnEditorDestroyed); // install application event filter QCoreApplication::instance()->installEventFilter(g_inplaceEditorHandler); return true; } void qtnRetainInplaceEditor() { ++g_inplaceEditorRetainCount; } void qtnReleaseInplaceEditor() { Q_ASSERT(g_inplaceEditorRetainCount > 0); --g_inplaceEditorRetainCount; } QWidget *qtnGetInplaceEdit() { return g_inplaceEditor; } void onInplaceWidgetDestroyed(QObject *object) { // set focus to parent of inplace widget QWidget *parent = qobject_cast(object->parent()); if (parent) parent->setFocus(); } bool qtnStopInplaceEdit(bool delete_later, bool restoreParentFocus) { if (!g_inplaceEditor) return false; if (g_inplaceEditorRetainCount > 0) return false; delete g_inplaceEditorHandler; g_inplaceEditorHandler = nullptr; if (restoreParentFocus) { QObject::connect( g_inplaceEditor, &QObject::destroyed, &onInplaceWidgetDestroyed); } if (delete_later) g_inplaceEditor->deleteLater(); else delete g_inplaceEditor; g_inplaceEditor = nullptr; return true; } bool hasParent(QObject *child, QObject *parent) { if (!child) return false; if (child == parent) return true; return hasParent(child->parent(), parent); } bool QtnInplaceEditorHandler::eventFilter(QObject *watched, QEvent *event) { Q_ASSERT(g_inplaceEditor); if (!event) return false; // try handle by base class if (QObject::eventFilter(watched, event)) return true; if (event->type() == QEvent::FocusIn) { if (!hasParent(QApplication::focusObject(), g_inplaceEditor)) qtnStopInplaceEdit(true, false); return false; } return false; } void QtnInplaceEditorHandler::OnEditorDestroyed(QObject *obj) { Q_UNUSED(obj); Q_ASSERT(obj == g_inplaceEditor); delete g_inplaceEditorHandler; g_inplaceEditorHandler = 0; g_inplaceEditor = 0; } ================================================ FILE: QtnProperty/Utils/InplaceEditing.h ================================================ /******************************************************************************* Copyright (c) 2012-2016 Alex Zhondin Copyright (C) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #ifndef INPLACE_EDITING_H #define INPLACE_EDITING_H #include "QtnProperty/Config.h" #include QTN_IMPORT_EXPORT void qtnRetainInplaceEditor(); QTN_IMPORT_EXPORT void qtnReleaseInplaceEditor(); QTN_IMPORT_EXPORT bool qtnStartInplaceEdit(QWidget *editor); QTN_IMPORT_EXPORT QWidget *qtnGetInplaceEdit(); QTN_IMPORT_EXPORT bool qtnStopInplaceEdit( bool delete_later = true, bool restoreParentFocus = true); #endif // INPLACE_EDITING_H ================================================ FILE: QtnProperty/Utils/MultilineTextDialog.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "MultilineTextDialog.h" #include "ui_MultilineTextDialog.h" #include MultilineTextDialog::MultilineTextDialog(QWidget *parent) : QDialog(parent) , ui(new Ui::MultilineTextDialog) { ui->setupUi(this); setWindowFlags((windowFlags() & ~(Qt::WindowContextHelpButtonHint)) | Qt::WindowCloseButtonHint | Qt::WindowMaximizeButtonHint); } MultilineTextDialog::~MultilineTextDialog() { delete ui; } void MultilineTextDialog::setReadOnly(bool value) { ui->plainTextEdit->setReadOnly(value); if (value) { ui->buttonBox->setStandardButtons(QDialogButtonBox::Close); } else { ui->buttonBox->setStandardButtons( QDialogButtonBox::Ok | QDialogButtonBox::Cancel); } } void MultilineTextDialog::setText(const QString &text) { ui->plainTextEdit->setPlainText(text); } QString MultilineTextDialog::getText() const { return ui->plainTextEdit->toPlainText(); } void MultilineTextDialog::on_buttonBox_clicked(QAbstractButton *button) { switch (ui->buttonBox->buttonRole(button)) { case QDialogButtonBox::AcceptRole: accept(); break; case QDialogButtonBox::RejectRole: reject(); break; default: break; } } ================================================ FILE: QtnProperty/Utils/MultilineTextDialog.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "QtnProperty/Config.h" #include namespace Ui { class MultilineTextDialog; } class QAbstractButton; class QTN_IMPORT_EXPORT MultilineTextDialog : public QDialog { Q_OBJECT public: explicit MultilineTextDialog(QWidget *parent = nullptr); virtual ~MultilineTextDialog(); void setReadOnly(bool value); void setText(const QString &text); QString getText() const; private slots: void on_buttonBox_clicked(QAbstractButton *button); private: Ui::MultilineTextDialog *ui; }; ================================================ FILE: QtnProperty/Utils/MultilineTextDialog.ui ================================================ MultilineTextDialog 0 0 400 300 true true 6 6 6 6 true QPlainTextEdit::WidgetWidth QDialogButtonBox::Cancel|QDialogButtonBox::Ok false ================================================ FILE: QtnProperty/Utils/QtnCompleterItemDelegate.cpp ================================================ #include "QtnCompleterItemDelegate.h" #include "QtnCompleterLineEdit.h" #include #include QtnCompleterItemDelegate::QtnCompleterItemDelegate( QtnCompleterLineEdit *lineEdit, QObject *parent) : QStyledItemDelegate(parent) , mLineEdit(lineEdit) { Q_ASSERT(mLineEdit); } void QtnCompleterItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { auto updatedOption = option; updatedOption.text.clear(); mLineEdit->style()->drawControl( QStyle::CE_ItemViewItem, &updatedOption, painter, nullptr); auto completer = mLineEdit->completer(); Q_ASSERT(completer); switch (completer->filterMode()) { case Qt::MatchStartsWith: case Qt::MatchContains: case Qt::MatchEndsWith: { auto subString = completer->completionPrefix(); auto currentStr = index.data().toString(); QFontMetrics fm(updatedOption.font); auto textRect = mLineEdit->style()->subElementRect( QStyle::SE_ItemViewItemText, &updatedOption); if (option.displayAlignment & Qt::AlignRight) { textRect.setRight(textRect.right() - mLineEdit->style()->pixelMetric( QStyle::PM_FocusFrameHMargin)); } else { textRect.setLeft(textRect.left() + mLineEdit->style()->pixelMetric( QStyle::PM_FocusFrameHMargin)); } int flags = Qt::TextSingleLine | int(option.displayAlignment); painter->save(); bool contains = false; auto highlightRect = textRect; switch (completer->filterMode()) { case Qt::MatchStartsWith: if (currentStr.startsWith( subString, completer->caseSensitivity())) { highlightRect.setWidth(fm.width(QString::fromRawData( currentStr.constData(), subString.length()))); contains = true; } break; case Qt::MatchContains: { int i = currentStr.indexOf( subString, 0, completer->caseSensitivity()); if (i >= 0) { highlightRect.setLeft(highlightRect.left() + fm.width(QString::fromRawData( currentStr.constData(), i))); highlightRect.setWidth(fm.width(QString::fromRawData( ¤tStr.constData()[i], subString.length()))); contains = true; } break; } case Qt::MatchEndsWith: if (currentStr.endsWith( subString, completer->caseSensitivity())) { highlightRect.setLeft(highlightRect.left() + fm.width( QString::fromRawData(currentStr.constData(), currentStr.length() - subString.length()))); contains = true; } break; } painter->setCompositionMode(QPainter::CompositionMode_Difference); if (contains) { painter->setPen(Qt::transparent); painter->setBrush(Qt::blue); painter->drawRect(highlightRect); } painter->setPen(Qt::white); painter->setBrush(Qt::transparent); painter->setFont(option.font); painter->drawText(textRect, flags, currentStr); painter->restore(); break; } default: qWarning("Unsupported filter mode"); break; } } ================================================ FILE: QtnProperty/Utils/QtnCompleterItemDelegate.h ================================================ #pragma once #include class QtnCompleterLineEdit; class QtnCompleterItemDelegate : public QStyledItemDelegate { Q_OBJECT QtnCompleterLineEdit *mLineEdit; public: QtnCompleterItemDelegate( QtnCompleterLineEdit *lineEdit, QObject *parent = nullptr); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; ================================================ FILE: QtnProperty/Utils/QtnCompleterLineEdit.cpp ================================================ #include "QtnCompleterLineEdit.h" #include "QtnCompleterItemDelegate.h" #include #include #include #include #include enum { POPUP_MARGIN = 6 }; class QtnCompleterLineEdit::ListView : public QListView { unsigned disableHide; public: ListView(); void beginDisableHide(); void endDisableHide(); virtual void setVisible(bool) override; }; class QtnCompleterLineEdit::Completer : public QCompleter { QtnCompleterLineEdit *mLineEdit; ListView *mListView; bool mCompleting; public: explicit Completer(QtnCompleterLineEdit *lineEdit); virtual ~Completer() override; virtual bool eventFilter(QObject *watched, QEvent *event) override; void complete(); }; QtnCompleterLineEdit::QtnCompleterLineEdit(QWidget *parent) : QLineEdit(parent) { mDefaultItemDelegate = new QtnCompleterItemDelegate(this); setCompleter(new Completer(this)); } QtnCompleterLineEdit::~QtnCompleterLineEdit() { setCompleter(nullptr); delete mDefaultItemDelegate; } QAbstractItemModel *QtnCompleterLineEdit::completerModel() const { return completer()->model(); } void QtnCompleterLineEdit::setCompleterModel(QAbstractItemModel *model) { auto oldModel = completerModel(); if (oldModel == model) return; if (oldModel) { QObject::disconnect(oldModel, &QAbstractItemModel::modelReset, this, &QtnCompleterLineEdit::complete); QObject::disconnect(oldModel, &QAbstractItemModel::dataChanged, this, &QtnCompleterLineEdit::complete); QObject::disconnect(oldModel, &QAbstractItemModel::rowsInserted, this, &QtnCompleterLineEdit::complete); QObject::disconnect(oldModel, &QAbstractItemModel::rowsRemoved, this, &QtnCompleterLineEdit::complete); } if (model) { QObject::connect(model, &QAbstractItemModel::modelReset, this, &QtnCompleterLineEdit::complete); QObject::connect(model, &QAbstractItemModel::dataChanged, this, &QtnCompleterLineEdit::complete); QObject::connect(model, &QAbstractItemModel::rowsInserted, this, &QtnCompleterLineEdit::complete); QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, &QtnCompleterLineEdit::complete); } completer()->setModel(model); completer()->popup()->setItemDelegate(mDefaultItemDelegate); } void QtnCompleterLineEdit::complete() { Q_ASSERT(dynamic_cast(this->completer())); auto completer = static_cast(this->completer()); auto unselectedPrefix = text(); if (selectionStart() >= 0) unselectedPrefix.resize(selectionStart()); auto model = completer->model(); bool hasMatch = false; for (int i = 0, count = model->rowCount(); i < count; i++) { if (model->data(model->index(i, 0)) .toString() .contains(unselectedPrefix, Qt::CaseInsensitive)) { hasMatch = true; break; } } if (!hasMatch) unselectedPrefix.clear(); if (unselectedPrefix != completer->completionPrefix()) { completer->setCompletionPrefix(unselectedPrefix); } completer->complete(); } bool QtnCompleterLineEdit::event(QEvent *e) { return QLineEdit::event(e); } QtnCompleterLineEdit::ListView::ListView() : disableHide(0) { setUniformItemSizes(true); setLayoutMode(Batched); setEditTriggers(NoEditTriggers); setResizeMode(Adjust); setTextElideMode(Qt::ElideNone); setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); setSelectionBehavior(SelectRows); setSelectionMode(SingleSelection); } inline void QtnCompleterLineEdit::ListView::beginDisableHide() { disableHide++; } inline void QtnCompleterLineEdit::ListView::endDisableHide() { disableHide--; } void QtnCompleterLineEdit::ListView::setVisible(bool yes) { if (yes || !disableHide) QListView::setVisible(yes); } QtnCompleterLineEdit::Completer::Completer(QtnCompleterLineEdit *lineEdit) : QCompleter(lineEdit) , mLineEdit(nullptr) //do not remove or eventFilter will crash , mListView(new ListView) , mCompleting(false) { setCompletionMode(QCompleter::PopupCompletion); setFilterMode(Qt::MatchContains); setWrapAround(true); setCaseSensitivity(Qt::CaseInsensitive); setPopup(mListView); mListView->viewport()->installEventFilter(this); mLineEdit = lineEdit; } QtnCompleterLineEdit::Completer::~Completer() { mListView->viewport()->removeEventFilter(this); } bool QtnCompleterLineEdit::Completer::eventFilter( QObject *watched, QEvent *event) { if (!mLineEdit) return QCompleter::eventFilter(watched, event); bool shouldComplete = false; bool disableHide = false; bool acceptEvent = false; bool escapePressed = false; bool finishEdit = false; if (!mLineEdit->isReadOnly()) { switch (event->type()) { case QEvent::FocusIn: shouldComplete = watched == mLineEdit; break; case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::MouseMove: { auto me = static_cast(event); auto localPos = mLineEdit->mapFromGlobal(me->globalPos()); if (mLineEdit->rect().contains(localPos)) { shouldComplete = !mListView->isVisible(); disableHide = true; if (watched != mLineEdit) { me->setLocalPos(localPos); mLineEdit->event(event); } break; } if (watched != mLineEdit) { bool outside = !mListView->isVisible() || !mListView->rect().contains(mListView->mapFromGlobal( static_cast(event)->globalPos())); if ((event->type() == QEvent::MouseButtonRelease && !outside) || (event->type() == QEvent::MouseButtonPress && outside)) { acceptEvent = true; finishEdit = true; } } break; } case QEvent::KeyPress: { auto ke = static_cast(event); switch (ke->key()) { case Qt::Key_Up: case Qt::Key_Down: case Qt::Key_PageDown: case Qt::Key_PageUp: break; case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_Home: case Qt::Key_End: acceptEvent = true; shouldComplete = true; break; case Qt::Key_Tab: case Qt::Key_Backtab: acceptEvent = true; break; case Qt::Key_Enter: case Qt::Key_Return: { setCompletionPrefix(mLineEdit->text()); acceptEvent = true; disableHide = true; shouldComplete = true; break; } case Qt::Key_Escape: escapePressed = true; if (watched == mLineEdit || !mListView->selectionModel()->hasSelection()) { break; } // fallthrough default: { acceptEvent = true; disableHide = true; shouldComplete = true; break; } } break; } default: break; } } if (disableHide) mListView->beginDisableHide(); bool result = QCompleter::eventFilter(watched, event); if (acceptEvent && !result && watched != mLineEdit && event->isAccepted()) { watched->event(event); result = true; } if (disableHide) mListView->endDisableHide(); if (finishEdit) { auto index = currentIndex(); if (index.isValid()) { emit activated(index); } else { QMetaObject::invokeMethod( mLineEdit, "editingFinished", Qt::QueuedConnection); } } else if (escapePressed) { if (watched != mLineEdit && mListView->selectionModel()->hasSelection()) { mListView->clearSelection(); } else { emit mLineEdit->escaped(); } result = true; } else if (shouldComplete) { mLineEdit->complete(); } return result; } void QtnCompleterLineEdit::Completer::complete() { if (mCompleting) return; mCompleting = true; auto popup = this->popup(); QRect rect(0, 0, qMin(popup->maximumWidth(), qMax(mLineEdit->width(), popup->sizeHintForColumn(0) + POPUP_MARGIN)), mLineEdit->height()); int h = popup->sizeHintForRow(0) * qMin(maxVisibleItems(), completionModel()->rowCount()) + POPUP_MARGIN; popup->setMinimumHeight(h); QCompleter::complete(rect); QScrollBar *hsb = popup->horizontalScrollBar(); if (hsb && hsb->isVisible()) h += popup->horizontalScrollBar()->sizeHint().height(); if (popup->height() < h) { popup->setMinimumHeight(h); QCompleter::complete(rect); } mCompleting = false; } ================================================ FILE: QtnProperty/Utils/QtnCompleterLineEdit.h ================================================ #pragma once #include "QtnProperty/Config.h" #include class QAbstractItemModel; class QtnCompleterItemDelegate; class QTN_IMPORT_EXPORT QtnCompleterLineEdit : public QLineEdit { Q_OBJECT class ListView; class Completer; QtnCompleterItemDelegate *mDefaultItemDelegate; public: explicit QtnCompleterLineEdit(QWidget *parent = nullptr); virtual ~QtnCompleterLineEdit() override; QAbstractItemModel *completerModel() const; void setCompleterModel(QAbstractItemModel *model); public slots: void complete(); signals: void escaped(); protected: virtual bool event(QEvent *e) override; private: using QLineEdit::setCompleter; }; ================================================ FILE: QtnProperty/Utils/QtnConnections.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "QtnConnections.h" #include void QtnConnections::disconnect() { for (auto &connection : *this) { QObject::disconnect(connection); } clear(); } QtnConnections::QtnConnections() {} QtnConnections::~QtnConnections() { if (!empty()) disconnect(); } ================================================ FILE: QtnProperty/Utils/QtnConnections.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "QtnProperty/Config.h" #include #include class QTN_IMPORT_EXPORT QtnConnections : public std::vector { Q_DISABLE_COPY(QtnConnections) public: void disconnect(); QtnConnections(); ~QtnConnections(); }; ================================================ FILE: QtnProperty/Utils/QtnInt64SpinBox.cpp ================================================ /******************************************************************************* Copyright 2017 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "QtnInt64SpinBox.h" #include #include #include #include class QtnInt64SpinBox::Validator : public QValidator { public: explicit Validator(QtnInt64SpinBox *parent); virtual State validate(QString &input, int &pos) const override; virtual void fixup(QString &input) const override; private: QtnInt64SpinBox *mParent; }; QtnInt64SpinBox::QtnInt64SpinBox(QWidget *parent) : QAbstractSpinBox(parent) , mValidator(new Validator(this)) , mValue(0) , mSingleStep(1) , mMinimum(std::numeric_limits::min()) , mMaximum(std::numeric_limits::max()) , mDisplayIntegerBase(10) , mPendingEmit(false) , mCleared(false) , mIgnoreCursorPosition(false) { setInputMethodHints(Qt::ImhDigitsOnly); auto edit = new QLineEdit(this); edit->setObjectName(QLatin1String("qt_spinbox_lineedit")); setLineEdit(edit); } void QtnInt64SpinBox::setPrefix(const QString &prefix) { if (mPrefix != prefix) { mPrefix = prefix; updateEdit(true); } } void QtnInt64SpinBox::setSuffix(const QString &suffix) { if (mSuffix != suffix) { mSuffix = suffix; updateEdit(true); } } QString QtnInt64SpinBox::cleanText() const { return textFromValue(mValue); } void QtnInt64SpinBox::setSingleStep(qint64 val) { mSingleStep = val; } void QtnInt64SpinBox::setMinimum(qint64 min) { setRange(min, mMaximum); } void QtnInt64SpinBox::setMaximum(qint64 max) { setRange(mMinimum, max); } void QtnInt64SpinBox::setSpecialValueText(const QString &txt) { if (specialValueText() != txt) { QAbstractSpinBox::setSpecialValueText(txt); updateEdit(true); } } void QtnInt64SpinBox::interpretText() { interpret(EmitIfChanged); } void QtnInt64SpinBox::setRange(qint64 min, qint64 max) { if (min > max) { qSwap(min, max); } if (mMinimum == min && mMaximum == max) { return; } mMinimum = min; mMaximum = max; updateEdit(true, true); } void QtnInt64SpinBox::setDisplayIntegerBase(int base) { // Falls back to base 10 on invalid bases (like QString) if (Q_UNLIKELY(base < 2 || base > 36)) { qWarning( "QtnInt64SpinBox::setDisplayIntegerBase: Invalid base (%d)", base); base = 10; } if (mDisplayIntegerBase != base) { mDisplayIntegerBase = base; updateEdit(true); } } QAbstractSpinBox::StepEnabled QtnInt64SpinBox::stepEnabled() const { if (isReadOnly()) return StepNone; if (wrapping()) return StepDownEnabled | StepUpEnabled; StepEnabled result; if (mValue > mMinimum) result |= StepDownEnabled; if (mValue < mMaximum) result |= StepUpEnabled; return result; } void QtnInt64SpinBox::setLineEdit(QLineEdit *lineEdit) { Q_ASSERT(nullptr != lineEdit); if (lineEdit == this->lineEdit()) { return; } if (lineEdit) { connect(lineEdit, &QLineEdit::textChanged, this, &QtnInt64SpinBox::onTextChanged); connect(lineEdit, &QLineEdit::cursorPositionChanged, this, &QtnInt64SpinBox::onCursorPositionChanged); } QAbstractSpinBox::setLineEdit(lineEdit); lineEdit->setValidator(mValidator); updateEdit(); } bool QtnInt64SpinBox::isSpecialValue() const { return mValue == mMinimum && !specialValueText().isEmpty(); } void QtnInt64SpinBox::clear() { QAbstractSpinBox::clear(); lineEdit()->setText(mPrefix + mSuffix); lineEdit()->setCursorPosition(mPrefix.size()); mCleared = true; } QSize QtnInt64SpinBox::sizeHint() const { if (mCachedSizeHint.isEmpty()) { mCachedSizeHint = calcSize(mPrefix + mSuffix + QLatin1Char(' '), lineEdit()->sizeHint().height()); } return mCachedSizeHint; } QSize QtnInt64SpinBox::minimumSizeHint() const { if (mCachedMinimumSizeHint.isEmpty()) { mCachedMinimumSizeHint = calcSize( mPrefix + QLatin1Char(' '), lineEdit()->minimumSizeHint().height()); } return mCachedMinimumSizeHint; } qint64 QtnInt64SpinBox::validateAndInterpret( QString &input, int *pos, QValidator::State *statePtr) const { int inputSize = input.size(); auto copy = input.trimmed(); if (copy.startsWith(mPrefix)) copy.remove(0, mPrefix.size()); if (copy.endsWith(mSuffix)) copy.resize(copy.size() - mSuffix.size()); auto locale = this->locale(); QValidator::State state = QValidator::Acceptable; qint64 num = mMinimum; if (mMinimum != mMaximum && (copy.isEmpty() || (mMinimum < 0 && copy == QLatin1String("-")) || (mMaximum >= 0 && copy == QLatin1String("+")))) { state = QValidator::Intermediate; } else if (copy.startsWith(QLatin1Char('-')) && mMinimum >= 0) { state = QValidator::Invalid; } else { bool ok = false; if (mDisplayIntegerBase != 10) { num = copy.toLongLong(&ok, mDisplayIntegerBase); } else { num = locale.toLongLong(copy, &ok); if (!ok && copy.contains(locale.groupSeparator()) && (mMaximum >= 1000 || mMinimum <= -1000)) { QString copy2 = copy; copy2.remove(locale.groupSeparator()); num = locale.toLongLong(copy2, &ok); } } if (!ok) { state = QValidator::Invalid; } else if (num >= mMinimum && num <= mMaximum) { state = QValidator::Acceptable; } else if (mMinimum == mMaximum) { state = QValidator::Invalid; } else { if ((num >= 0 && num > mMaximum) || (num < 0 && num < mMinimum)) { state = QValidator::Invalid; } else { state = QValidator::Intermediate; } } } if (state != QValidator::Acceptable) num = mMaximum > 0 ? mMinimum : mMaximum; input = mPrefix + copy + mSuffix; if (pos) { (*pos) -= inputSize - input.size(); } if (statePtr) { *statePtr = state; } return num; } QSize QtnInt64SpinBox::calcSize(const QString &fixedContent, int h) const { //Use the prefix and range to calculate the minimumSizeHint ensurePolished(); const QFontMetrics fm(fontMetrics()); int w = 0; QString s; s = textFromValue(mMinimum); s.truncate(18); s += fixedContent; w = qMax(w, fm.width(s)); s = textFromValue(mMaximum); s.truncate(18); s += fixedContent; w = qMax(w, fm.width(s)); s = specialValueText(); if (!s.isEmpty()) { w = qMax(w, fm.width(s)); } w += 2; // cursor blinking space QStyleOptionSpinBox opt; initStyleOption(&opt); QSize hint(w, h); return style() ->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this) .expandedTo(QApplication::globalStrut()); } QValidator::State QtnInt64SpinBox::validate(QString &input, int &pos) const { QValidator::State state; validateAndInterpret(input, &pos, &state); return state; } qint64 QtnInt64SpinBox::valueFromText(const QString &text) const { QString copy = text; return validateAndInterpret(copy, nullptr, nullptr); } QString QtnInt64SpinBox::textFromValue(qint64 val) const { QString str; if (mDisplayIntegerBase != 10) { const QLatin1String prefix = val < 0 ? QLatin1String("-") : QLatin1String(); str = prefix + QString::number(qAbs(val), mDisplayIntegerBase); } else { str = locale().toString(val); if (!isGroupSeparatorShown()) str.remove(locale().groupSeparator()); } return str; } void QtnInt64SpinBox::fixup(QString &str) const { if (!isGroupSeparatorShown()) str.remove(locale().groupSeparator()); } void QtnInt64SpinBox::stepBy(int steps) { auto old = mValue; QString input = lineEdit()->text(); int pos = lineEdit()->cursorPosition(); bool dontStep = false; EmitPolicy ep = EmitIfChanged; if (mPendingEmit) { dontStep = validate(input, pos) != QValidator::Acceptable; mCleared = false; interpret(NeverEmit); if (mValue != old) { ep = AlwaysEmit; } } if (!dontStep) { qint64 step = mSingleStep * steps; qint64 newValue; if (step < 0 && quint64(-step) >= quint64(mValue - mMinimum)) { newValue = mMinimum; } else if (step > 0 && quint64(step) >= quint64(mMaximum - mValue)) { newValue = mMaximum; } else { newValue = mValue + step; } setValue(newValue, ep); } else if (ep == AlwaysEmit) { emitSignals(); } selectAll(); } void QtnInt64SpinBox::keyPressEvent(QKeyEvent *event) { if (!event->text().isEmpty() && lineEdit()->cursorPosition() < mPrefix.size()) { lineEdit()->setCursorPosition(mPrefix.size()); } QAbstractSpinBox::keyPressEvent(event); switch (event->key()) { case Qt::Key_Enter: case Qt::Key_Return: interpret(keyboardTracking() ? AlwaysEmit : EmitIfChanged); selectAll(); break; default: break; } if (mCleared && !lineEdit()->text().isEmpty()) { mCleared = false; } } void QtnInt64SpinBox::showEvent(QShowEvent *event) { QAbstractSpinBox::showEvent(event); updateEdit(); } void QtnInt64SpinBox::changeEvent(QEvent *event) { QAbstractSpinBox::changeEvent(event); if (event->type() == QEvent::ActivationChange) { if (!isActiveWindow()) { if (mPendingEmit) interpret(EmitIfChanged); } } } void QtnInt64SpinBox::focusOutEvent(QFocusEvent *event) { QAbstractSpinBox::focusOutEvent(event); if (mPendingEmit) interpret(EmitIfChanged); updateEdit(); } void QtnInt64SpinBox::closeEvent(QCloseEvent *event) { QAbstractSpinBox::closeEvent(event); if (mPendingEmit) interpret(EmitIfChanged); } void QtnInt64SpinBox::hideEvent(QHideEvent *event) { QAbstractSpinBox::hideEvent(event); if (mPendingEmit) interpret(EmitIfChanged); } void QtnInt64SpinBox::updateEdit(bool withGeometry, bool withValue) { if (withValue && !isSpecialValue()) { setValue(mValue); } else if (!mCleared) { auto edit = lineEdit(); bool isSpecialValue = this->isSpecialValue(); const QString newText = isSpecialValue ? specialValueText() : mPrefix + textFromValue(mValue) + mSuffix; if (newText == edit->text()) return; const bool empty = edit->text().isEmpty(); int cursor = edit->cursorPosition(); int selectedSize = edit->selectedText().size(); const QSignalBlocker blocker(edit); edit->setText(newText); if (!isSpecialValue) { cursor = qBound( mPrefix.size(), cursor, edit->text().size() - mSuffix.size()); if (selectedSize > 0) { edit->setSelection(cursor, selectedSize); } else { edit->setCursorPosition(empty ? mPrefix.size() : cursor); } } update(); } if (withGeometry) { mCachedMinimumSizeHint = QSize(); mCachedSizeHint = QSize(); updateGeometry(); } } void QtnInt64SpinBox::onTextChanged(const QString &text) { mPendingEmit = true; if (keyboardTracking()) { QString input = text; int pos = lineEdit()->cursorPosition(); QValidator::State state = validate(input, pos); if (state == QValidator::Acceptable) { setValue(valueFromText(input)); mPendingEmit = false; } } } void QtnInt64SpinBox::onCursorPositionChanged(int oldPos, int newPos) { auto edit = lineEdit(); if (!edit->hasSelectedText() && !mIgnoreCursorPosition && !isSpecialValue()) { mIgnoreCursorPosition = true; bool allowSelection = true; int pos = -1; if (newPos < mPrefix.size() && newPos != 0) { if (oldPos == 0) { allowSelection = false; pos = mPrefix.size(); } else { pos = oldPos; } } else if (newPos > edit->text().size() - mSuffix.size() && newPos != edit->text().size()) { if (oldPos == edit->text().size()) { pos = edit->text().size() - mSuffix.size(); allowSelection = false; } else { pos = edit->text().size(); } } if (pos != -1) { const int selSize = edit->selectionStart() >= 0 && allowSelection ? (edit->selectedText().size() * (newPos < pos ? -1 : 1)) - newPos + pos : 0; const QSignalBlocker blocker(edit); if (selSize != 0) { edit->setSelection(pos - selSize, selSize); } else { edit->setCursorPosition(pos); } } mIgnoreCursorPosition = false; } } void QtnInt64SpinBox::setValue(qint64 value, EmitPolicy ep, bool updateEdit) { Q_ASSERT(value >= mMinimum); Q_ASSERT(value <= mMaximum); auto old = mValue; mValue = value; mPendingEmit = false; mCleared = false; if (updateEdit) { this->updateEdit(); } else { update(); } if (ep == AlwaysEmit || (ep == EmitIfChanged && old != mValue)) { emitSignals(); } } void QtnInt64SpinBox::emitSignals() { mPendingEmit = false; emit valueChanged(lineEdit()->text()); emit valueChanged(mValue); } void QtnInt64SpinBox::interpret(EmitPolicy ep) { if (mCleared) return; qint64 v = 0; bool doInterpret = true; QString tmp = lineEdit()->text(); int pos = lineEdit()->cursorPosition(); const int oldpos = pos; if (validate(tmp, pos) != QValidator::Acceptable) { const QString copy = tmp; fixup(tmp); doInterpret = tmp != copy && (validate(tmp, pos) == QValidator::Acceptable); if (!doInterpret) { if (correctionMode() == CorrectToNearestValue) { if (mMinimum < v) { v = std::min(v, mMaximum); } else { v = mMinimum; } } else { v = mValue; } } } if (doInterpret) { v = valueFromText(tmp); } setValue(v, ep, true); if (oldpos != pos) lineEdit()->setCursorPosition(pos); } void QtnInt64SpinBox::setValue(qint64 val) { if (val < mMinimum) val = mMinimum; if (val > mMaximum) val = mMaximum; if (mValue != val) { setValue(val, EmitIfChanged); } } QtnInt64SpinBox::Validator::Validator(QtnInt64SpinBox *parent) : QValidator(parent) , mParent(parent) { setObjectName(QLatin1String("qt_int64_spinboxvalidator")); } QValidator::State QtnInt64SpinBox::Validator::validate( QString &input, int &pos) const { auto specialText = mParent->specialValueText(); if (!specialText.isEmpty() && input == specialText) return QValidator::Acceptable; auto &prefix = mParent->mPrefix; if (!prefix.isEmpty() && !input.startsWith(prefix)) { input.prepend(prefix); pos += prefix.length(); } auto &suffix = mParent->mSuffix; if (!suffix.isEmpty() && !input.endsWith(suffix)) input.append(suffix); return mParent->validate(input, pos); } void QtnInt64SpinBox::Validator::fixup(QString &input) const { mParent->fixup(input); } ================================================ FILE: QtnProperty/Utils/QtnInt64SpinBox.h ================================================ /******************************************************************************* Copyright 2017 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "QtnProperty/Config.h" #include class QTN_IMPORT_EXPORT QtnInt64SpinBox : public QAbstractSpinBox { Q_OBJECT Q_DISABLE_COPY(QtnInt64SpinBox) Q_PROPERTY(QString suffix READ suffix WRITE setSuffix) Q_PROPERTY(QString prefix READ prefix WRITE setPrefix) Q_PROPERTY(QString cleanText READ cleanText) Q_PROPERTY(qint64 minimum READ minimum WRITE setMinimum) Q_PROPERTY(qint64 maximum READ maximum WRITE setMaximum) Q_PROPERTY(qint64 singleStep READ singleStep WRITE setSingleStep) Q_PROPERTY( qint64 value READ value WRITE setValue NOTIFY valueChanged USER true) Q_PROPERTY(int displayIntegerBase READ displayIntegerBase WRITE setDisplayIntegerBase) Q_PROPERTY(bool isSpecialValue READ isSpecialValue) Q_PROPERTY(QString specialValueText READ specialValueText WRITE setSpecialValueText) public: explicit QtnInt64SpinBox(QWidget *parent = nullptr); inline qint64 value() const; inline const QString &prefix() const; void setPrefix(const QString &prefix); inline const QString &suffix() const; void setSuffix(const QString &suffix); QString cleanText() const; inline qint64 singleStep() const; void setSingleStep(qint64 val); inline qint64 minimum() const; void setMinimum(qint64 min); inline qint64 maximum() const; void setMaximum(qint64 max); void setSpecialValueText(const QString &txt); void interpretText(); void setRange(qint64 min, qint64 max); inline int displayIntegerBase() const; void setDisplayIntegerBase(int base); virtual StepEnabled stepEnabled() const override; void setLineEdit(QLineEdit *lineEdit); bool isSpecialValue() const; virtual void clear() override; virtual QSize sizeHint() const override; virtual QSize minimumSizeHint() const override; protected: virtual QValidator::State validate(QString &input, int &pos) const override; virtual qint64 valueFromText(const QString &text) const; virtual QString textFromValue(qint64 val) const; virtual void fixup(QString &str) const override; virtual void stepBy(int steps) override; virtual void keyPressEvent(QKeyEvent *event) override; virtual void showEvent(QShowEvent *event) override; virtual void changeEvent(QEvent *event) override; virtual void focusOutEvent(QFocusEvent *event) override; virtual void closeEvent(QCloseEvent *event) override; virtual void hideEvent(QHideEvent *event) override; void updateEdit(bool withGeometry = false, bool withValue = false); private: enum EmitPolicy { EmitIfChanged, AlwaysEmit, NeverEmit }; void onTextChanged(const QString &text); void onCursorPositionChanged(int oldPos, int newPos); void setValue(qint64 value, EmitPolicy ep, bool updateEdit = true); void emitSignals(); void interpret(EmitPolicy ep); qint64 validateAndInterpret( QString &input, int *pos, QValidator::State *statePtr) const; QSize calcSize(const QString &fixedContent, int h) const; public slots: void setValue(qint64 val); signals: void valueChanged(qint64); void valueChanged(const QString &); private: class Validator; friend class Validator; Validator *mValidator; qint64 mValue; qint64 mSingleStep; qint64 mMinimum; qint64 mMaximum; int mDisplayIntegerBase; bool mPendingEmit; bool mCleared; bool mIgnoreCursorPosition; mutable QSize mCachedSizeHint; mutable QSize mCachedMinimumSizeHint; QString mPrefix; QString mSuffix; }; qint64 QtnInt64SpinBox::value() const { return mValue; } const QString &QtnInt64SpinBox::prefix() const { return mPrefix; } const QString &QtnInt64SpinBox::suffix() const { return mSuffix; } qint64 QtnInt64SpinBox::singleStep() const { return mSingleStep; } qint64 QtnInt64SpinBox::minimum() const { return mMinimum; } qint64 QtnInt64SpinBox::maximum() const { return mMaximum; } int QtnInt64SpinBox::displayIntegerBase() const { return mDisplayIntegerBase; } ================================================ FILE: QtnProperty/VarProperty.cpp ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #include "VarProperty.h" #include "PropertyBase.h" #include "PropertySet.h" #include "Core/PropertyBool.h" #include "Core/PropertyInt.h" #include "Core/PropertyUInt.h" #include "Core/PropertyDouble.h" #include "Core/PropertyQString.h" VarProperty::VarProperty(QObject *parent, VarProperty::Type type, const QString &name, int index, const QVariant &value) : QObject(parent) , varParent(nullptr) , value(type == Value ? value : QVariant()) , name(name) , index(index) , type(type) { } void VarProperty::ChangePropertyValue(const QVariant &value, QVariant *dest) { if (this->value != value) { this->value = value; if (nullptr != dest) { auto top = TopParent(); Q_ASSERT(nullptr != top); *dest = top->CreateVariant(); } } } void VarProperty::RemoveFromParent() { if (nullptr != varParent) { auto &siblings = varParent->varChildren; auto it = std::find(siblings.begin(), siblings.end(), this); if (it != siblings.end()) { siblings.erase(it); } } } VarProperty *VarProperty::Duplicate(VarProperty *child, int newIndex) { Q_ASSERT(nullptr != child); return AddChild(new VarProperty(nullptr, VarProperty::Value, "", newIndex, child->CreateVariant()), newIndex); } VarProperty *VarProperty::Duplicate(VarProperty *child, const QString &newName) { Q_ASSERT(nullptr != child); return AddChild(new VarProperty( nullptr, VarProperty::Value, newName, -1, child->CreateVariant())); } VarProperty *VarProperty::Duplicate(int new_index) { Q_ASSERT(nullptr != varParent); return varParent->Duplicate(this, new_index); } VarProperty *VarProperty::Duplicate(const QString &new_name) { Q_ASSERT(nullptr != varParent); return varParent->Duplicate(this, new_name); } VarProperty *VarProperty::AddChild(VarProperty *child, int index) { if (index < 0) index = static_cast(varChildren.size()); child->varParent = this; varChildren.insert(varChildren.begin() + index, child); return child; } VarProperty *VarProperty::AddChild(int index, const QVariant &value) { return AddChild( new VarProperty(nullptr, GetTypeFromValue(value), "", index, value), index); } VarProperty *VarProperty::AddChild(const QString &name, const QVariant &value) { return AddChild( new VarProperty(nullptr, GetTypeFromValue(value), name, -1, value)); } VarProperty::Type VarProperty::GetTypeFromValue(const QVariant &value) { Type type; switch (value.type()) { case QVariant::Hash: case QVariant::Map: type = Map; break; case QVariant::StringList: case QVariant::List: type = List; break; default: type = Value; break; } return type; } VarProperty::Type VarProperty::GetType() const { return type; } QVariant::Type VarProperty::GetVariantType() const { switch (type) { case Value: return value.type(); case List: return QVariant::List; case Map: return QVariant::Map; } return QVariant::Invalid; } int VarProperty::GetIndex() const { return index; } bool VarProperty::SetIndex(int newIndex) { if (index != newIndex) { index = newIndex; if (newIndex >= 0) name = QStringLiteral("[%1]").arg(QString::number(newIndex)); return true; } return false; } const QString &VarProperty::GetName() const { return name; } bool VarProperty::SetName(const QString &newName) { if (index < 0 && name != newName) { name = newName; return true; } return false; } VarProperty *VarProperty::TopParent() { auto p = varParent; if (nullptr == p) return this; while (nullptr != p) { auto next_p = p->varParent; if (nullptr == next_p) return p; p = next_p; } return nullptr; } VarProperty *VarProperty::VarParent() { return varParent; } VarProperty::VarChildren &VarProperty::GetChildren() { return varChildren; } int VarProperty::GetChildrenCount() const { return int(varChildren.size()); } void VarProperty::SetValue(const QVariant &value) { this->value = value; switch (type) { case Map: case List: for (auto child : varChildren) { child->SetValue(QVariant()); child->setParent(nullptr); delete child; } varChildren.clear(); break; case Value: break; } type = Value; } QVariant VarProperty::CreateVariant() const { switch (type) { case List: { QVariantList list; for (auto child : varChildren) { list.append(child->CreateVariant()); } return QVariant(list); } case Map: { QVariantMap map; for (auto child : varChildren) { map.insert(child->name, child->CreateVariant()); } return QVariant(map); } default: break; } return value; } bool VarProperty::IsChildNameAvailable( const QString &name, VarProperty *skip) const { for (auto prop : varChildren) { if (skip == prop) continue; if (prop->name == name) return false; } return true; } QtnPropertyBase *VarProperty::NewExtraProperty(QtnPropertySet *set, const QVariant &value, const QString &key, int index, VarProperty *mapParent, const RegisterPropertyCallback ®isterProperty) { QtnProperty *prop = nullptr; QString name(key); if (index >= 0) name = QString("[%1]").arg(QString::number(index)); auto type = value.type(); switch (type) { case QVariant::Hash: case QVariant::Map: { return NewExtraPropertySet( set, value.toMap(), mapParent, name, index, registerProperty); } case QVariant::StringList: case QVariant::List: { return NewExtraPropertyList( set, value.toList(), mapParent, name, index, registerProperty); } case QVariant::Int: { auto p = new QtnPropertyInt(set); p->setId(PID_EXTRA_INT); p->setValue(value.toInt()); prop = p; break; } case QVariant::UInt: { auto p = new QtnPropertyUInt(set); p->setId(PID_EXTRA_UINT); p->setValue(value.toUInt()); prop = p; break; } case QVariant::LongLong: case QVariant::ULongLong: case QVariant::Double: { auto p = new QtnPropertyDouble(set); p->setId(PID_EXTRA_FLOAT); p->setValue(value.toDouble()); prop = p; break; } case QVariant::Bool: { auto p = new QtnPropertyBool(set); p->setId(PID_EXTRA_BOOL); p->setValue(value.toBool()); prop = p; break; } default: { auto p = new QtnPropertyQString(set); p->setId(PID_EXTRA_STRING); p->setValue(value.toString()); prop = p; break; } } if (nullptr != prop) { if (set) { set->addChildProperty(prop); } auto varprop = new VarProperty(prop, VarProperty::Value, name, index, value); if (nullptr != mapParent) mapParent->AddChild(varprop, index); prop->setName(name); registerProperty(prop); } return prop; } bool VarProperty::PropertyValueAccept( const QtnProperty *property, void *valueToAccept, QVariant *dest) { switch (property->id()) { case VarProperty::PID_EXTRA: case VarProperty::PID_EXTRA_STRING: case VarProperty::PID_EXTRA_INT: case VarProperty::PID_EXTRA_UINT: case VarProperty::PID_EXTRA_FLOAT: case VarProperty::PID_EXTRA_BOOL: { auto var_property = property->findChild( QString(), Qt::FindDirectChildrenOnly); QVariant value; if (nullptr != valueToAccept) { switch (property->id()) { case PID_EXTRA_STRING: value = QVariant(*(QtnPropertyQString::ValueTypeStore *) valueToAccept); break; case PID_EXTRA_INT: value = QVariant( *(QtnPropertyInt::ValueTypeStore *) valueToAccept); break; case PID_EXTRA_UINT: value = QVariant( *(QtnPropertyUInt::ValueTypeStore *) valueToAccept); break; case PID_EXTRA_FLOAT: value = QVariant(*( QtnPropertyDouble::ValueTypeStore *) valueToAccept); break; case PID_EXTRA_BOOL: value = QVariant( *(QtnPropertyBool::ValueTypeStore *) valueToAccept); break; default: value = *(QVariant *) valueToAccept; break; } } var_property->ChangePropertyValue(value, dest); return true; } } return false; } QtnPropertySet *VarProperty::NewExtraPropertySet(QtnPropertySet *parent, const QVariantMap &map, VarProperty *mapParent, const QString &name, int index, const RegisterPropertyCallback ®isterProperty) { auto set = new QtnPropertySet(parent); if (parent) { parent->addChildProperty(set); } auto varprop = new VarProperty(set, VarProperty::Map, name, index, QVariant()); if (nullptr != mapParent) mapParent->AddChild(varprop, index); mapParent = varprop; set->setId(PID_EXTRA); set->setName(name); for (auto it = map.begin(); it != map.end(); ++it) { auto &key = it.key(); auto &value = it.value(); NewExtraProperty(set, value, key, -1, mapParent, registerProperty); } return set; } QtnPropertySet *VarProperty::NewExtraPropertyList(QtnPropertySet *parent, const QVariantList &list, VarProperty *mapParent, const QString &name, int index, const RegisterPropertyCallback ®isterProperty) { auto set = new QtnPropertySet(parent); if (parent) { parent->addChildProperty(set); } auto varprop = new VarProperty(set, VarProperty::List, name, index, QVariant()); if (nullptr != mapParent) mapParent->AddChild(varprop, index); mapParent = varprop; set->setId(PID_EXTRA); set->setName(name); int len = list.size(); for (int i = 0; i < len; i++) { auto &value = list.at(i); NewExtraProperty(set, value, QString(), i, mapParent, registerProperty); } return set; } ================================================ FILE: QtnProperty/VarProperty.h ================================================ /******************************************************************************* Copyright (c) 2015-2019 Alexandra Cherdantseva Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *******************************************************************************/ #pragma once #include "Config.h" #include #include #include #include class QtnPropertyBase; class QtnProperty; class QtnPropertySet; class QTN_IMPORT_EXPORT VarProperty : public QObject { Q_OBJECT public: enum Type { Value, List, Map }; typedef std::function RegisterPropertyCallback; typedef std::vector VarChildren; VarProperty(QObject *parent, Type type, const QString &name, int index, const QVariant &value); void ChangePropertyValue(const QVariant &value, QVariant *dest = nullptr); void RemoveFromParent(); VarProperty *Duplicate(VarProperty *child, int newIndex); VarProperty *Duplicate(VarProperty *child, const QString &newName); VarProperty *Duplicate(int new_index); VarProperty *Duplicate(const QString &new_name); VarProperty *AddChild(VarProperty *child, int index = -1); VarProperty *AddChild(int index, const QVariant &value); VarProperty *AddChild(const QString &name, const QVariant &value); static Type GetTypeFromValue(const QVariant &value); Type GetType() const; QVariant::Type GetVariantType() const; int GetIndex() const; bool SetIndex(int newIndex); const QString &GetName() const; bool SetName(const QString &newName); VarProperty *TopParent(); VarProperty *VarParent(); VarChildren &GetChildren(); int GetChildrenCount() const; void SetValue(const QVariant &value); QVariant CreateVariant() const; bool IsChildNameAvailable(const QString &name, VarProperty *skip) const; static QtnPropertyBase *NewExtraProperty(QtnPropertySet *set, const QVariant &value, const QString &key, int index, VarProperty *mapParent, const RegisterPropertyCallback ®isterProperty); static bool PropertyValueAccept(const QtnProperty *property, void *valueToAccept, QVariant *dest = nullptr); enum { PID_EXTRA = 1, PID_EXTRA_STRING, PID_EXTRA_INT, PID_EXTRA_UINT, PID_EXTRA_FLOAT, PID_EXTRA_BOOL, PID_EXTRA_TOTAL }; private: static QtnPropertySet *NewExtraPropertySet(QtnPropertySet *parent, const QVariantMap &map, VarProperty *mapParent, const QString &name, int index, const RegisterPropertyCallback ®isterProperty); static QtnPropertySet *NewExtraPropertyList(QtnPropertySet *parent, const QVariantList &list, VarProperty *mapParent, const QString &name, int index, const RegisterPropertyCallback ®isterProperty); VarProperty *varParent; VarChildren varChildren; QVariant value; QString name; int index; Type type; }; ================================================ FILE: QtnProperty.pro ================================================ TEMPLATE = subdirs SUBDIRS += \ QtnProperty \ PEG \ Tests \ Demo Tests.depends = PEG QtnProperty Demo.depends = PEG QtnProperty OTHER_FILES += \ README.md \ CHANGELOG \ LICENSE \ AUTHORS \ TODO ================================================ FILE: QtnPropertyDepend.pri ================================================ isEmpty(QTNPROPERTY_BIN) { include($$PWD/Internal/BaseConfig.pri) } QTNPROPERTY_PATH = $$PWD isEmpty(QTNPROPERTY_LIB) { QTNPROPERTY_LIB = $$QTNPROPERTY_BIN } QTNPROPERTY_LIBNAME = QtnProperty qtnproperty_dynamic:QTNPROPERTY_LIBNAME = $$join(QTNPROPERTY_LIBNAME, , , 2) win32 { msvc:PRE_TARGETDEPS += $$QTNPROPERTY_LIB/$$join(QTNPROPERTY_LIBNAME, , , .lib) else:PRE_TARGETDEPS += $$QTNPROPERTY_LIB/$$join(QTNPROPERTY_LIBNAME, , lib, .a) } qtnproperty_dynamic { DEFINES += QTN_DYNAMIC_IMPORT macx { DYNAMIC_LIBS.files += $$QTNPROPERTY_LIB/$$join(QTNPROPERTY_LIBNAME, , lib, .dylib) } } else { unix { PRE_TARGETDEPS += $$QTNPROPERTY_LIB/$$join(QTNPROPERTY_LIBNAME, , lib, .a) } } LIBS += -L$$QTNPROPERTY_LIB LIBS += -l$$QTNPROPERTY_LIBNAME INCLUDEPATH += $$QTNPROPERTY_PATH ================================================ FILE: README.md ================================================ [![Build Status](https://travis-ci.org/qtinuum/QtnProperty.svg?branch=master)](https://travis-ci.org/qtinuum/QtnProperty) # QtnProperty This is user and programmer friendly properties for Qt framework. See [wiki](https://github.com/qtinuum/QtnProperty/wiki) for some details. # Overview There are some limitations of standard Qt property system. This project is an attempt to make better properties. The key features are: * Properties hierarchy (properties can be organized in hierarchy at any depth) * Property widget to observe and edit properties in uniform way * Signals before and after property has changed * Property description - short text which help user to understand meaning and purpose of the property * Property state - property can be disabled or hidden at any moment * Serialization via QDataStream * Set/Get property value to/from QVariant and QString * Scripting support * Delegates to customize look and feel properties in property widget * PEG (property/enum generator) - it's optional tool like Qt moc which generates properties hierarchy from QML like files into C++ code. New Features in v2.0.0 * **Multi-properties with QtnMultipleProperty.** It is useful when you want to show properties of multiple objects at once. When values of objects's properties differ it shows grayed (**Multiple properties**). When you set a new property value, it will be changed in every dependent object. Multi-property set can be created with qtnCreateQObjectMultiPropertySet function defined in [QObjectPropertySet.h](https://github.com/qtinuum/QtnProperty/blob/master/QtnProperty/QObjectPropertySet.h) or from custom property sets in a loop with qtnPropertiesToMultiSet function where target argument is a multi-property set, and source argument is a source property set you want to join. * **QVariant properties with QtnCustomPropertyWidget.** You can edit QVariant as property set / add/remove subproperties in QVariantMap or QVariantList, copy/paste variant properties. * **Integer 64 properties** QtnPropertyInt64 QtnPropertyUInt64 * **Floating point variants of QPoint, QSize, QRect properties** * **Overriding QtnPropertyDelegateFactory for QtnPropertySet** * **Improvements to sync objects values and property editors** * **Translations EN_RU** Some screenshots of the Demo application: ![Demo_screenshot_linux](Docs/img/Demo1.png) ![Demo_screenshot_win](Docs/img/DemoWin.png) # How to build **Requirements:** 1. Qt 5.9 framework or later 2. Optional: Flex 2.6.4 and Bison 3.1.1 (for Windows can be found [here](https://github.com/lexxmark/winflexbison)) if you build QtnPEG tool **To build:** mkdir path_to_build cd path_to_build qmake path_to_QtnProperty/QtnProperty.pro -r make Or just open path\_to\_QtnProperty/QtnProperty.pro file in Qt Creator and build all. Generated libraries and executables will be placed into the target specific folders. For example: bin-linux-gcc-x86_64 bin-osx-clang-x86_64 bin-win32-msvc-i386 bin-win32-msvc-clang-x86_64 bin-win32-gcc-i386 bin-win32-gcc-x86_64 **To run tests and demo, go to one of the binary folders and run:** ./QtnPropertyTests ./QtnPropertyDemo QtnProperty project consists of four submodules: 1. **QtnProperty** library - property classes. By default it is a static library. If you need a dynamic library, you should run **qmake** with **CONFIG+=qtnproperty_dynamic** argument 3. **QtnPEG** tool - optional executable to generate C++ code for property sets from simple QML like files (*.pef files) 4. **QtnPropertyTests** - tests for QtnPropertyCore library 5. **QtnPropertyDemo** - demo application # How to use ## Step 1. To have QtnProperty in your project you should include QtnPropertyDepend.pri file into your pro file. Example: MyProject.pro ------------- ``` TEMPLATE = subdirs SUBDIRS += \ QtnProperty \ Application QtnProperty.file = path_to/QtnProperty/QtnProperty.pro Application.depends = \ QtnProperty ``` Application/Application.pro --------------------------- ``` QT += core gui widgets script TEMPLATE = app include(path_to/QtnProperty/QtnPropertyDepend.pri) # this will add QtnProperty root to include path and will link the library to your app. ``` ## Step 2. Then you can manually create property sets in your C++ code, create QtnPropertyWidget or QtnPropertyView widgets and assign property set to the widget: ```C++ class Ui_MainWindow { public: QtnPropertyWidget *centralWidget; ... }; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); m_propertySet = new QtnPropertySet(this) auto floatValue = qtnCreateProperty(m_propertySet); floatValue->setName("value"); floatValue->setDisplayName(tr("Value")); floatValue->setDescription(tr("Float value")); floatValue->setMaxValue(1.f); floatValue->setMinValue(0.f); floatValue->setStepValue(0.1f); floatValue->setValue(0.3f); auto textColor = qtnCreateProperty(m_propertySet); textColor->setName("textColor"); textColor->setDisplayName(tr("TextColor")); textColor->setDescription(tr("Foreground text color")); textColor->setValue(QColor(0, 0, 0)); ui->centralWidget->setPropertySet(m_propertySet); } ``` This example will show you something like this: ![Example_screenshot_windows](Docs/img/Example1.png) ## Step 3. If you want to use *.pef files to generate properties C++ code you need to build QtnPEG executable. ## Step 4. To use *.pef files in your project you should do the following in your pro file: * Define PEG_TOOL variable as full path to the QtnPEG executable * include PEG.pri file * list all *.pef files in PEG_SOURCES variable ```C++ include(path_to/QtnProperty/PEG/PEG.pri) PEG_SOURCES += TextEditor.pef ``` ## Step 5. Write *.pef file with propertyset declaration. See [wiki](https://github.com/qtinuum/QtnProperty/wiki/Property-Enum-file-format-(*.pef)) for more info. For example TextEditor.pef: ```C++ #include "QtnProperty/PropertyCore.h" property_set TextEditor { Bool enableWrapping { description = "Enable/disable text wrapping"; value = true; } Bool replaceTabsWithSpaces { description = "Automatically replace tabs with spaces"; value = false; slot propertyDidChange { tabSize.switchState(QtnPropertyStateImmutable, !replaceTabsWithSpaces); } } UInt tabSize { description = "Number of spaces to be placed."; state = QtnPropertyStateImmutable; value = 4; } } ``` ## Step 6. Include generated TextEditor.peg.h and TextEditor.peg.cpp files into your project. ## Step 7. Now you can use QtnPropertySetTextEditor class (defined in generated files) in your C++ code like this: ```C++ QtnPropertySetTextEditor params; params.enableWrapping = false; if (params.replaceTabsWithSpaces) document.replaceTabsWithSpaces(params.tabSize); ``` Video of GUI testing using Froglogic (c) Squish test framework is [here](https://www.youtube.com/watch?v=lCmM13vPWBU). ================================================ FILE: TODO ================================================ PropertyArray Implement PropertySetForm - property widgets on form Make wrapper propertyset for QObject derived classes (implement Enum and EnumFlags cases) Save/Load via XML PropertyTypes: 1. Date/Time 2. Bitmap ??? 4. Cursor 5. Icon owner feature???? How to define default PropertySet? command line parameters for PEG refactor PEG to support bison 3.0 refactor PEG to generate thread-safe property_set constructors (static variables) QtDesigner plugin Help pef files syntax highlight CMake support Tests: 2. Property equal (==) 3. Property <, > for numerics 4. make PropertySetAllPropertyTypes with subproperties 5. add benchmarks implement ReportError method ================================================ FILE: Tests/PEG/test.pef ================================================ #include "QtnProperty/Enum.h" #include_cpp #include_h "QtnProperty/PropertyCore.h" #include_h "QtnProperty/PropertyGUI.h" property_set Test1 { id = 1; description = "Test property_set description"; state =0 ; Int a { id = 2; description = "Descripion"; value = 5; stepValue = -1; maxValue = 10; } QString text{ id = 3; value=QString("#^{};"); description = "defrf\"sde\"""deerf3rf" "derf r g\r\nreg r{}""dfrgerg" "fwrewre"; } } property_set Test2{ id = 4; } code_h { // declaration void aaa(); } property_set Test3 { id = 5; property_set YY yy { id = 6; description = QString("ss")+QString("ss"); // rectangle property QRect rect {value = QRect(10, 10, 10, 10);} QString s; } property_set SS iis { id = 7; Bool a{ value = true; id = 8; } property_set AA aa { id = 9; code_h { private: bool m_s; } code_cpp { // AA cpp code } } } Bool u { id = 10; value = true; slot propertyDidChange { // sub u propertyDidChange } } slot propertyDidChange { // this propertyDidChange } slot u.propertyWillChange { // u.propertyWillChange code } /* * external property set **/ extern property_set Test2 xx {} extern property_set Test2 tt; extern property_set SS s { a.value = false; slot a.propertyWillChange { yy.rect = QRect(1, 1, 1, 1); // ss propertyWillChange } slot a.propertyValueAccept { // s.a.propertyValueAccept } } Bool ww {id = 11; } BoolCallback bc { id = 12; callbackValueGet = [this]()->bool { return ww; }; callbackValueAccepted = [](bool value)->bool { if (value) { return true; } else { return false; } }; callbackValueEqual = [](bool)->bool { return false; }; callbackValueSet = [this](bool value, QtnPropertyChangeReason /*reason*/) { m_s = value; }; } code_h { public: bool m_s; } } code_cpp{ void aaa() { } } enum LANGUAGE { ENG(3, "English") } enum TYPE{} enum COLOR { RED (10, "Red"), BLUE (22, "Blue") hidden obsolete, YELLOW (1, "Yellow") } enum MASK { ONE (1, "One"), TWO (2, "Two"), FOUR (4, "Four") } property_set AllPropertyTypes { id = 13; Bool bp { id = 14; } BoolCallback bpc { callbackValueGet = [this]() { return _b; }; callbackValueSet = [this](bool v, QtnPropertyChangeReason /*reason*/) { _b = v; }; id = 15; } Int ip { id = 16; } IntCallback ipc { callbackValueGet = [this]() { return _i; }; callbackValueSet = [this](qint32 v, QtnPropertyChangeReason /*reason*/) { _i =v; }; id = 17; } UInt up { id = 18; } UIntCallback upc { callbackValueGet = [this]() { return _ui; }; callbackValueSet = [this](quint32 v, QtnPropertyChangeReason /*reason*/) { _ui = v; }; id = 19; } Float fp { id = 20; } FloatCallback fpc { callbackValueGet = [this]() { return _f; }; callbackValueSet = [this](float v, QtnPropertyChangeReason /*reason*/) { _f = v; }; id = 21; } Double dp { id = 22; } DoubleCallback dpc { callbackValueGet = [this]() { return _d; }; callbackValueSet = [this](double v, QtnPropertyChangeReason /*reason*/) { _d = v; }; id = 23; } QString sp { id = 24; } QStringCallback spc { callbackValueGet = [this]() { return _s; }; callbackValueSet = [this](QString v, QtnPropertyChangeReason /*reason*/) { _s = v; }; id = 25; } QRect rp { id = 26; } QRectCallback rpc { callbackValueGet = [this]() { return _r; }; callbackValueSet = [this](QRect v, QtnPropertyChangeReason /*reason*/) { _r = v; }; id = 27; } QPoint pp { id = 28; } QPointCallback ppc { callbackValueGet = [this]() { return _p; }; callbackValueSet = [this](QPoint v, QtnPropertyChangeReason /*reason*/) { _p = v; }; id = 29; } QSize szp { id = 30; } QSizeCallback szpc { callbackValueGet = [this]() { return _sz; }; callbackValueSet = [this](QSize v, QtnPropertyChangeReason /*reason*/) { _sz = v; }; id = 31; } Enum ep { enumInfo = &COLOR::info(); value = COLOR::BLUE; id = 32; } EnumCallback epc { enumInfo = &COLOR::info(); callbackValueGet = [this]() { return _e; }; callbackValueSet = [this](QtnEnumValueType v, QtnPropertyChangeReason /*reason*/) { _e = v; }; id = 33; } EnumFlags efp { enumInfo = &MASK::info(); value = MASK::ONE|MASK::FOUR; id = 34; } EnumFlagsCallback efpc { enumInfo = &MASK::info(); callbackValueGet = [this]() { return _ef; }; callbackValueSet = [this](QtnEnumFlagsValueType v, QtnPropertyChangeReason /*reason*/) { _ef = v; }; id = 35; } QColor cp { value = QColor(Qt::blue); id = 36; } QColorCallback cpc { callbackValueGet = [this]() { return _cl; }; callbackValueSet = [this](QColor v, QtnPropertyChangeReason /*reason*/) { _cl = v; }; id = 37; } QFont fnp { value = QFont("Courier", 10); id = 38; } QFontCallback fnpc { callbackValueGet = [this]() { return _fn; }; callbackValueSet = [this](QFont v, QtnPropertyChangeReason /*reason*/) { _fn = v; }; id = 39; } Button bttn { id = 40; } QPointF ppf { id = 41; } QPointFCallback ppfc { callbackValueGet = [this]() { return _pf; }; callbackValueSet = [this](QPointF v, QtnPropertyChangeReason /*reason*/) { _pf = v; }; id = 42; } QRectF rpf { id = 43; } QRectFCallback rpfc { callbackValueGet = [this]() { return _rf; }; callbackValueSet = [this](QRectF v, QtnPropertyChangeReason /*reason*/) { _rf = v; }; id = 44; } QSizeF szpf { id = 45; } QSizeFCallback szpfc { callbackValueGet = [this]() { return _szf; }; callbackValueSet = [this](QSizeF v, QtnPropertyChangeReason /*reason*/) { _szf = v; }; id = 46; } AllPropertyTypes() : _b(true) { _i =12; _ui = 9; _f = 0.2f; _d = 32.4; _s = "name"; _r = QRect(10, 10, 10, 10); _rf = QRectF(10.1, 10.2, 10.3, 10.4); _p = QPoint(9, 2); _pf = QPointF(9.9, 2.2); _sz = QSize(33, 21); _szf = QSizeF(33.0, 21.9); _e = COLOR::RED; _ef = MASK::ONE|MASK::FOUR; _cl = QColor(Qt::red); _fn = QFont("Arial", 19); } ~AllPropertyTypes() { _b = false; } code_h { private: bool _b; qint32 _i; quint32 _ui; float _f; double _d; QString _s; QRect _r; QRectF _rf; QPoint _p; QPointF _pf; QSize _sz; QSizeF _szf; QtnEnumValueType _e; QtnEnumFlagsValueType _ef; QColor _cl; QFont _fn; } } /* * NONE(-1, "None") hidden, ENG(0, "English"), FR(1, "French"), GM(2, "German") enum MY_TYPE { MY_TYPE1(1, "My type 1"), MY_TYPE2(2, "My type 2") } */ enum MY_TYPE { MY_TYPE1(1, "My type 1"), MY_TYPE2(2, "My type 2") } property_set Test12 { Enum p { value = MY_TYPE::MY_TYPE1; enumInfo = &MY_TYPE::info(); } } ================================================ FILE: Tests/PEG/test.peg.cpp ================================================ #include "test.peg.h" #include QtnPropertySetTest1::QtnPropertySetTest1(QObject* parent) : QtnPropertySet(parent) , a(*qtnCreateProperty(this)) , text(*qtnCreateProperty(this)) { init(); connectSlots(); connectDelegates(); } QtnPropertySetTest1::~QtnPropertySetTest1() { disconnectSlots(); } QtnPropertySetTest1& QtnPropertySetTest1::operator=(const QtnPropertySetTest1& other) { Q_UNUSED(other); a = other.a; text = other.text; return *this; } QtnPropertySet* QtnPropertySetTest1::createNewImpl(QObject* parentForNew) const { return new QtnPropertySetTest1(parentForNew); } QtnPropertySet* QtnPropertySetTest1::createCopyImpl(QObject* parentForCopy) const { QtnPropertySetTest1* p = new QtnPropertySetTest1(parentForCopy); *p = *this; return p; } bool QtnPropertySetTest1::copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) { Q_UNUSED(ignoreMask); auto theCopyFrom = qobject_cast(propertySetCopyFrom); if (!theCopyFrom) return false; if (!(theCopyFrom->a.state() & ignoreMask)) { a = theCopyFrom->a; } if (!(theCopyFrom->text.state() & ignoreMask)) { text = theCopyFrom->text; } return true; } void QtnPropertySetTest1::init() { static QString Test1_name = QStringLiteral("Test1"); setName(Test1_name); static QString description = "Test property_set description"; setDescription(description); setId(1); setState(0); // start children initialization static QString a_name = QStringLiteral("a"); a.setName(a_name); static QString a_description = "Descripion"; a.setDescription(a_description); a.setId(2); a.setMaxValue(10); a.setStepValue(-1); a.setValue(5); static QString text_name = QStringLiteral("text"); text.setName(text_name); static QString text_description = "defrf\"sde\"""deerf3rf" "derf r g\r\nreg r{}""dfrgerg" "fwrewre"; text.setDescription(text_description); text.setId(3); text.setValue(QString("#^{};")); // end children initialization } void QtnPropertySetTest1::connectSlots() { } void QtnPropertySetTest1::disconnectSlots() { } void QtnPropertySetTest1::connectDelegates() { } QtnPropertySetTest2::QtnPropertySetTest2(QObject* parent) : QtnPropertySet(parent) { init(); connectSlots(); connectDelegates(); } QtnPropertySetTest2::~QtnPropertySetTest2() { disconnectSlots(); } QtnPropertySetTest2& QtnPropertySetTest2::operator=(const QtnPropertySetTest2& other) { Q_UNUSED(other); return *this; } QtnPropertySet* QtnPropertySetTest2::createNewImpl(QObject* parentForNew) const { return new QtnPropertySetTest2(parentForNew); } QtnPropertySet* QtnPropertySetTest2::createCopyImpl(QObject* parentForCopy) const { QtnPropertySetTest2* p = new QtnPropertySetTest2(parentForCopy); *p = *this; return p; } bool QtnPropertySetTest2::copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) { Q_UNUSED(ignoreMask); auto theCopyFrom = qobject_cast(propertySetCopyFrom); if (!theCopyFrom) return false; return true; } void QtnPropertySetTest2::init() { static QString Test2_name = QStringLiteral("Test2"); setName(Test2_name); setId(4); } void QtnPropertySetTest2::connectSlots() { } void QtnPropertySetTest2::disconnectSlots() { } void QtnPropertySetTest2::connectDelegates() { } QtnPropertySetYY::QtnPropertySetYY(QObject* parent) : QtnPropertySet(parent) , rect(*qtnCreateProperty(this)) , s(*qtnCreateProperty(this)) { init(); connectSlots(); connectDelegates(); } QtnPropertySetYY::~QtnPropertySetYY() { disconnectSlots(); } QtnPropertySetYY& QtnPropertySetYY::operator=(const QtnPropertySetYY& other) { Q_UNUSED(other); rect = other.rect; s = other.s; return *this; } QtnPropertySet* QtnPropertySetYY::createNewImpl(QObject* parentForNew) const { return new QtnPropertySetYY(parentForNew); } QtnPropertySet* QtnPropertySetYY::createCopyImpl(QObject* parentForCopy) const { QtnPropertySetYY* p = new QtnPropertySetYY(parentForCopy); *p = *this; return p; } bool QtnPropertySetYY::copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) { Q_UNUSED(ignoreMask); auto theCopyFrom = qobject_cast(propertySetCopyFrom); if (!theCopyFrom) return false; if (!(theCopyFrom->rect.state() & ignoreMask)) { rect = theCopyFrom->rect; } if (!(theCopyFrom->s.state() & ignoreMask)) { s = theCopyFrom->s; } return true; } void QtnPropertySetYY::init() { static QString yy_name = QStringLiteral("yy"); setName(yy_name); static QString description = QString("ss")+QString("ss"); setDescription(description); setId(6); // start children initialization static QString rect_name = QStringLiteral("rect"); rect.setName(rect_name); rect.setValue(QRect(10, 10, 10, 10)); static QString s_name = QStringLiteral("s"); s.setName(s_name); // end children initialization } void QtnPropertySetYY::connectSlots() { } void QtnPropertySetYY::disconnectSlots() { } void QtnPropertySetYY::connectDelegates() { } QtnPropertySetAA::QtnPropertySetAA(QObject* parent) : QtnPropertySet(parent) { init(); connectSlots(); connectDelegates(); } QtnPropertySetAA::~QtnPropertySetAA() { disconnectSlots(); } QtnPropertySetAA& QtnPropertySetAA::operator=(const QtnPropertySetAA& other) { Q_UNUSED(other); return *this; } QtnPropertySet* QtnPropertySetAA::createNewImpl(QObject* parentForNew) const { return new QtnPropertySetAA(parentForNew); } QtnPropertySet* QtnPropertySetAA::createCopyImpl(QObject* parentForCopy) const { QtnPropertySetAA* p = new QtnPropertySetAA(parentForCopy); *p = *this; return p; } bool QtnPropertySetAA::copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) { Q_UNUSED(ignoreMask); auto theCopyFrom = qobject_cast(propertySetCopyFrom); if (!theCopyFrom) return false; return true; } void QtnPropertySetAA::init() { static QString aa_name = QStringLiteral("aa"); setName(aa_name); setId(9); } void QtnPropertySetAA::connectSlots() { } void QtnPropertySetAA::disconnectSlots() { } void QtnPropertySetAA::connectDelegates() { } // AA cpp code QtnPropertySetSS::QtnPropertySetSS(QObject* parent) : QtnPropertySet(parent) , a(*qtnCreateProperty(this)) , aa(*qtnCreateProperty(this)) { init(); connectSlots(); connectDelegates(); } QtnPropertySetSS::~QtnPropertySetSS() { disconnectSlots(); } QtnPropertySetSS& QtnPropertySetSS::operator=(const QtnPropertySetSS& other) { Q_UNUSED(other); a = other.a; aa = other.aa; return *this; } QtnPropertySet* QtnPropertySetSS::createNewImpl(QObject* parentForNew) const { return new QtnPropertySetSS(parentForNew); } QtnPropertySet* QtnPropertySetSS::createCopyImpl(QObject* parentForCopy) const { QtnPropertySetSS* p = new QtnPropertySetSS(parentForCopy); *p = *this; return p; } bool QtnPropertySetSS::copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) { Q_UNUSED(ignoreMask); auto theCopyFrom = qobject_cast(propertySetCopyFrom); if (!theCopyFrom) return false; if (!(theCopyFrom->a.state() & ignoreMask)) { a = theCopyFrom->a; } aa.copyValues(&theCopyFrom->aa, ignoreMask); return true; } void QtnPropertySetSS::init() { static QString iis_name = QStringLiteral("iis"); setName(iis_name); setId(7); // start children initialization static QString a_name = QStringLiteral("a"); a.setName(a_name); a.setId(8); a.setValue(true); static QString aa_name = QStringLiteral("aa"); aa.setName(aa_name); aa.setId(9); // end children initialization } void QtnPropertySetSS::connectSlots() { } void QtnPropertySetSS::disconnectSlots() { } void QtnPropertySetSS::connectDelegates() { } QtnPropertySetTest3::QtnPropertySetTest3(QObject* parent) : QtnPropertySet(parent) , yy(*qtnCreateProperty(this)) , iis(*qtnCreateProperty(this)) , u(*qtnCreateProperty(this)) , xx(*qtnCreateProperty(this)) , tt(*qtnCreateProperty(this)) , s(*qtnCreateProperty(this)) , ww(*qtnCreateProperty(this)) , bc(*qtnCreateProperty(this)) { init(); connectSlots(); connectDelegates(); } QtnPropertySetTest3::~QtnPropertySetTest3() { disconnectSlots(); } QtnPropertySetTest3& QtnPropertySetTest3::operator=(const QtnPropertySetTest3& other) { Q_UNUSED(other); yy = other.yy; iis = other.iis; u = other.u; xx = other.xx; tt = other.tt; s = other.s; ww = other.ww; bc = other.bc; return *this; } QtnPropertySet* QtnPropertySetTest3::createNewImpl(QObject* parentForNew) const { return new QtnPropertySetTest3(parentForNew); } QtnPropertySet* QtnPropertySetTest3::createCopyImpl(QObject* parentForCopy) const { QtnPropertySetTest3* p = new QtnPropertySetTest3(parentForCopy); *p = *this; return p; } bool QtnPropertySetTest3::copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) { Q_UNUSED(ignoreMask); auto theCopyFrom = qobject_cast(propertySetCopyFrom); if (!theCopyFrom) return false; yy.copyValues(&theCopyFrom->yy, ignoreMask); iis.copyValues(&theCopyFrom->iis, ignoreMask); if (!(theCopyFrom->u.state() & ignoreMask)) { u = theCopyFrom->u; } xx.copyValues(&theCopyFrom->xx, ignoreMask); tt.copyValues(&theCopyFrom->tt, ignoreMask); s.copyValues(&theCopyFrom->s, ignoreMask); if (!(theCopyFrom->ww.state() & ignoreMask)) { ww = theCopyFrom->ww; } if (!(theCopyFrom->bc.state() & ignoreMask)) { bc = theCopyFrom->bc; } return true; } void QtnPropertySetTest3::init() { static QString Test3_name = QStringLiteral("Test3"); setName(Test3_name); setId(5); // start children initialization static QString yy_name = QStringLiteral("yy"); yy.setName(yy_name); static QString yy_description = QString("ss")+QString("ss"); yy.setDescription(yy_description); yy.setId(6); static QString iis_name = QStringLiteral("iis"); iis.setName(iis_name); iis.setId(7); static QString u_name = QStringLiteral("u"); u.setName(u_name); u.setId(10); u.setValue(true); static QString xx_name = QStringLiteral("xx"); xx.setName(xx_name); static QString tt_name = QStringLiteral("tt"); tt.setName(tt_name); static QString s_name = QStringLiteral("s"); s.setName(s_name); s.a.setValue(false); static QString ww_name = QStringLiteral("ww"); ww.setName(ww_name); ww.setId(11); static QString bc_name = QStringLiteral("bc"); bc.setName(bc_name); bc.setCallbackValueAccepted([](bool value)->bool { if (value) { return true; } else { return false; } }); bc.setCallbackValueEqual([](bool)->bool { return false; }); bc.setCallbackValueGet([this]()->bool { return ww; }); bc.setCallbackValueSet([this](bool value, QtnPropertyChangeReason /*reason*/) { m_s = value; }); bc.setId(12); // end children initialization } void QtnPropertySetTest3::connectSlots() { QObject::connect(this, &QtnProperty::propertyDidChange, this, &QtnPropertySetTest3::on_propertyDidChange); QObject::connect(&u, &QtnProperty::propertyWillChange, this, &QtnPropertySetTest3::on_u_propertyWillChange); QObject::connect(&u, &QtnProperty::propertyDidChange, this, &QtnPropertySetTest3::on_u_propertyDidChange); QObject::connect(&s.a, &QtnProperty::propertyValueAccept, this, &QtnPropertySetTest3::on_s_a_propertyValueAccept); QObject::connect(&s.a, &QtnProperty::propertyWillChange, this, &QtnPropertySetTest3::on_s_a_propertyWillChange); } void QtnPropertySetTest3::disconnectSlots() { QObject::disconnect(this, &QtnProperty::propertyDidChange, this, &QtnPropertySetTest3::on_propertyDidChange); QObject::disconnect(&u, &QtnProperty::propertyWillChange, this, &QtnPropertySetTest3::on_u_propertyWillChange); QObject::disconnect(&u, &QtnProperty::propertyDidChange, this, &QtnPropertySetTest3::on_u_propertyDidChange); QObject::disconnect(&s.a, &QtnProperty::propertyValueAccept, this, &QtnPropertySetTest3::on_s_a_propertyValueAccept); QObject::disconnect(&s.a, &QtnProperty::propertyWillChange, this, &QtnPropertySetTest3::on_s_a_propertyWillChange); } void QtnPropertySetTest3::on_propertyDidChange(QtnPropertyChangeReason reason) { Q_UNUSED(reason); // this propertyDidChange } void QtnPropertySetTest3::on_u_propertyWillChange(QtnPropertyChangeReason reason, QtnPropertyValuePtr newValue, int typeId) { Q_UNUSED(reason); Q_UNUSED(newValue);Q_UNUSED(typeId); // u.propertyWillChange code } void QtnPropertySetTest3::on_u_propertyDidChange(QtnPropertyChangeReason reason) { Q_UNUSED(reason); // sub u propertyDidChange } void QtnPropertySetTest3::on_s_a_propertyValueAccept(QtnPropertyValuePtr valueToAccept, bool* accept) { Q_UNUSED(valueToAccept); Q_UNUSED(accept); // s.a.propertyValueAccept } void QtnPropertySetTest3::on_s_a_propertyWillChange(QtnPropertyChangeReason reason, QtnPropertyValuePtr newValue, int typeId) { Q_UNUSED(reason); Q_UNUSED(newValue);Q_UNUSED(typeId); yy.rect = QRect(1, 1, 1, 1); // ss propertyWillChange } void QtnPropertySetTest3::connectDelegates() { } void aaa() { } static QtnEnumInfo& create_LANGUAGE_info() { QVector staticValues; staticValues.append(QtnEnumValueInfo(LANGUAGE::ENG, "ENG", "English")); static QtnEnumInfo enumInfo("LANGUAGE", staticValues); return enumInfo; } const QtnEnumInfo& LANGUAGE::info() { static QtnEnumInfo& enumInfo = create_LANGUAGE_info(); return enumInfo; } static QtnEnumInfo& create_TYPE_info() { QVector staticValues; static QtnEnumInfo enumInfo("TYPE", staticValues); return enumInfo; } const QtnEnumInfo& TYPE::info() { static QtnEnumInfo& enumInfo = create_TYPE_info(); return enumInfo; } static QtnEnumInfo& create_COLOR_info() { QVector staticValues; staticValues.append(QtnEnumValueInfo(COLOR::RED, "RED", "Red")); staticValues.append(QtnEnumValueInfo(COLOR::BLUE, "BLUE", "Blue", QtnEnumValueStateHidden | QtnEnumValueStateObsolete)); staticValues.append(QtnEnumValueInfo(COLOR::YELLOW, "YELLOW", "Yellow")); static QtnEnumInfo enumInfo("COLOR", staticValues); return enumInfo; } const QtnEnumInfo& COLOR::info() { static QtnEnumInfo& enumInfo = create_COLOR_info(); return enumInfo; } static QtnEnumInfo& create_MASK_info() { QVector staticValues; staticValues.append(QtnEnumValueInfo(MASK::ONE, "ONE", "One")); staticValues.append(QtnEnumValueInfo(MASK::TWO, "TWO", "Two")); staticValues.append(QtnEnumValueInfo(MASK::FOUR, "FOUR", "Four")); static QtnEnumInfo enumInfo("MASK", staticValues); return enumInfo; } const QtnEnumInfo& MASK::info() { static QtnEnumInfo& enumInfo = create_MASK_info(); return enumInfo; } QtnPropertySetAllPropertyTypes::QtnPropertySetAllPropertyTypes(QObject* parent) : QtnPropertySet(parent) , bp(*qtnCreateProperty(this)) , bpc(*qtnCreateProperty(this)) , ip(*qtnCreateProperty(this)) , ipc(*qtnCreateProperty(this)) , up(*qtnCreateProperty(this)) , upc(*qtnCreateProperty(this)) , fp(*qtnCreateProperty(this)) , fpc(*qtnCreateProperty(this)) , dp(*qtnCreateProperty(this)) , dpc(*qtnCreateProperty(this)) , sp(*qtnCreateProperty(this)) , spc(*qtnCreateProperty(this)) , rp(*qtnCreateProperty(this)) , rpc(*qtnCreateProperty(this)) , pp(*qtnCreateProperty(this)) , ppc(*qtnCreateProperty(this)) , szp(*qtnCreateProperty(this)) , szpc(*qtnCreateProperty(this)) , ep(*qtnCreateProperty(this)) , epc(*qtnCreateProperty(this)) , efp(*qtnCreateProperty(this)) , efpc(*qtnCreateProperty(this)) , cp(*qtnCreateProperty(this)) , cpc(*qtnCreateProperty(this)) , fnp(*qtnCreateProperty(this)) , fnpc(*qtnCreateProperty(this)) , bttn(*qtnCreateProperty(this)) , ppf(*qtnCreateProperty(this)) , ppfc(*qtnCreateProperty(this)) , rpf(*qtnCreateProperty(this)) , rpfc(*qtnCreateProperty(this)) , szpf(*qtnCreateProperty(this)) , szpfc(*qtnCreateProperty(this)) , _b(true) { _i =12; _ui = 9; _f = 0.2f; _d = 32.4; _s = "name"; _r = QRect(10, 10, 10, 10); _rf = QRectF(10.1, 10.2, 10.3, 10.4); _p = QPoint(9, 2); _pf = QPointF(9.9, 2.2); _sz = QSize(33, 21); _szf = QSizeF(33.0, 21.9); _e = COLOR::RED; _ef = MASK::ONE|MASK::FOUR; _cl = QColor(Qt::red); _fn = QFont("Arial", 19); init(); connectSlots(); connectDelegates(); } QtnPropertySetAllPropertyTypes::~QtnPropertySetAllPropertyTypes() { _b = false; disconnectSlots(); } QtnPropertySetAllPropertyTypes& QtnPropertySetAllPropertyTypes::operator=(const QtnPropertySetAllPropertyTypes& other) { Q_UNUSED(other); bp = other.bp; bpc = other.bpc; ip = other.ip; ipc = other.ipc; up = other.up; upc = other.upc; fp = other.fp; fpc = other.fpc; dp = other.dp; dpc = other.dpc; sp = other.sp; spc = other.spc; rp = other.rp; rpc = other.rpc; pp = other.pp; ppc = other.ppc; szp = other.szp; szpc = other.szpc; ep = other.ep; epc = other.epc; efp = other.efp; efpc = other.efpc; cp = other.cp; cpc = other.cpc; fnp = other.fnp; fnpc = other.fnpc; bttn = other.bttn; ppf = other.ppf; ppfc = other.ppfc; rpf = other.rpf; rpfc = other.rpfc; szpf = other.szpf; szpfc = other.szpfc; return *this; } QtnPropertySet* QtnPropertySetAllPropertyTypes::createNewImpl(QObject* parentForNew) const { return new QtnPropertySetAllPropertyTypes(parentForNew); } QtnPropertySet* QtnPropertySetAllPropertyTypes::createCopyImpl(QObject* parentForCopy) const { QtnPropertySetAllPropertyTypes* p = new QtnPropertySetAllPropertyTypes(parentForCopy); *p = *this; return p; } bool QtnPropertySetAllPropertyTypes::copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) { Q_UNUSED(ignoreMask); auto theCopyFrom = qobject_cast(propertySetCopyFrom); if (!theCopyFrom) return false; if (!(theCopyFrom->bp.state() & ignoreMask)) { bp = theCopyFrom->bp; } if (!(theCopyFrom->bpc.state() & ignoreMask)) { bpc = theCopyFrom->bpc; } if (!(theCopyFrom->ip.state() & ignoreMask)) { ip = theCopyFrom->ip; } if (!(theCopyFrom->ipc.state() & ignoreMask)) { ipc = theCopyFrom->ipc; } if (!(theCopyFrom->up.state() & ignoreMask)) { up = theCopyFrom->up; } if (!(theCopyFrom->upc.state() & ignoreMask)) { upc = theCopyFrom->upc; } if (!(theCopyFrom->fp.state() & ignoreMask)) { fp = theCopyFrom->fp; } if (!(theCopyFrom->fpc.state() & ignoreMask)) { fpc = theCopyFrom->fpc; } if (!(theCopyFrom->dp.state() & ignoreMask)) { dp = theCopyFrom->dp; } if (!(theCopyFrom->dpc.state() & ignoreMask)) { dpc = theCopyFrom->dpc; } if (!(theCopyFrom->sp.state() & ignoreMask)) { sp = theCopyFrom->sp; } if (!(theCopyFrom->spc.state() & ignoreMask)) { spc = theCopyFrom->spc; } if (!(theCopyFrom->rp.state() & ignoreMask)) { rp = theCopyFrom->rp; } if (!(theCopyFrom->rpc.state() & ignoreMask)) { rpc = theCopyFrom->rpc; } if (!(theCopyFrom->pp.state() & ignoreMask)) { pp = theCopyFrom->pp; } if (!(theCopyFrom->ppc.state() & ignoreMask)) { ppc = theCopyFrom->ppc; } if (!(theCopyFrom->szp.state() & ignoreMask)) { szp = theCopyFrom->szp; } if (!(theCopyFrom->szpc.state() & ignoreMask)) { szpc = theCopyFrom->szpc; } if (!(theCopyFrom->ep.state() & ignoreMask)) { ep = theCopyFrom->ep; } if (!(theCopyFrom->epc.state() & ignoreMask)) { epc = theCopyFrom->epc; } if (!(theCopyFrom->efp.state() & ignoreMask)) { efp = theCopyFrom->efp; } if (!(theCopyFrom->efpc.state() & ignoreMask)) { efpc = theCopyFrom->efpc; } if (!(theCopyFrom->cp.state() & ignoreMask)) { cp = theCopyFrom->cp; } if (!(theCopyFrom->cpc.state() & ignoreMask)) { cpc = theCopyFrom->cpc; } if (!(theCopyFrom->fnp.state() & ignoreMask)) { fnp = theCopyFrom->fnp; } if (!(theCopyFrom->fnpc.state() & ignoreMask)) { fnpc = theCopyFrom->fnpc; } if (!(theCopyFrom->bttn.state() & ignoreMask)) { bttn = theCopyFrom->bttn; } if (!(theCopyFrom->ppf.state() & ignoreMask)) { ppf = theCopyFrom->ppf; } if (!(theCopyFrom->ppfc.state() & ignoreMask)) { ppfc = theCopyFrom->ppfc; } if (!(theCopyFrom->rpf.state() & ignoreMask)) { rpf = theCopyFrom->rpf; } if (!(theCopyFrom->rpfc.state() & ignoreMask)) { rpfc = theCopyFrom->rpfc; } if (!(theCopyFrom->szpf.state() & ignoreMask)) { szpf = theCopyFrom->szpf; } if (!(theCopyFrom->szpfc.state() & ignoreMask)) { szpfc = theCopyFrom->szpfc; } return true; } void QtnPropertySetAllPropertyTypes::init() { static QString AllPropertyTypes_name = QStringLiteral("AllPropertyTypes"); setName(AllPropertyTypes_name); setId(13); // start children initialization static QString bp_name = QStringLiteral("bp"); bp.setName(bp_name); bp.setId(14); static QString bpc_name = QStringLiteral("bpc"); bpc.setName(bpc_name); bpc.setCallbackValueGet([this]() { return _b; }); bpc.setCallbackValueSet([this](bool v, QtnPropertyChangeReason /*reason*/) { _b = v; }); bpc.setId(15); static QString ip_name = QStringLiteral("ip"); ip.setName(ip_name); ip.setId(16); static QString ipc_name = QStringLiteral("ipc"); ipc.setName(ipc_name); ipc.setCallbackValueGet([this]() { return _i; }); ipc.setCallbackValueSet([this](qint32 v, QtnPropertyChangeReason /*reason*/) { _i =v; }); ipc.setId(17); static QString up_name = QStringLiteral("up"); up.setName(up_name); up.setId(18); static QString upc_name = QStringLiteral("upc"); upc.setName(upc_name); upc.setCallbackValueGet([this]() { return _ui; }); upc.setCallbackValueSet([this](quint32 v, QtnPropertyChangeReason /*reason*/) { _ui = v; }); upc.setId(19); static QString fp_name = QStringLiteral("fp"); fp.setName(fp_name); fp.setId(20); static QString fpc_name = QStringLiteral("fpc"); fpc.setName(fpc_name); fpc.setCallbackValueGet([this]() { return _f; }); fpc.setCallbackValueSet([this](float v, QtnPropertyChangeReason /*reason*/) { _f = v; }); fpc.setId(21); static QString dp_name = QStringLiteral("dp"); dp.setName(dp_name); dp.setId(22); static QString dpc_name = QStringLiteral("dpc"); dpc.setName(dpc_name); dpc.setCallbackValueGet([this]() { return _d; }); dpc.setCallbackValueSet([this](double v, QtnPropertyChangeReason /*reason*/) { _d = v; }); dpc.setId(23); static QString sp_name = QStringLiteral("sp"); sp.setName(sp_name); sp.setId(24); static QString spc_name = QStringLiteral("spc"); spc.setName(spc_name); spc.setCallbackValueGet([this]() { return _s; }); spc.setCallbackValueSet([this](QString v, QtnPropertyChangeReason /*reason*/) { _s = v; }); spc.setId(25); static QString rp_name = QStringLiteral("rp"); rp.setName(rp_name); rp.setId(26); static QString rpc_name = QStringLiteral("rpc"); rpc.setName(rpc_name); rpc.setCallbackValueGet([this]() { return _r; }); rpc.setCallbackValueSet([this](QRect v, QtnPropertyChangeReason /*reason*/) { _r = v; }); rpc.setId(27); static QString pp_name = QStringLiteral("pp"); pp.setName(pp_name); pp.setId(28); static QString ppc_name = QStringLiteral("ppc"); ppc.setName(ppc_name); ppc.setCallbackValueGet([this]() { return _p; }); ppc.setCallbackValueSet([this](QPoint v, QtnPropertyChangeReason /*reason*/) { _p = v; }); ppc.setId(29); static QString szp_name = QStringLiteral("szp"); szp.setName(szp_name); szp.setId(30); static QString szpc_name = QStringLiteral("szpc"); szpc.setName(szpc_name); szpc.setCallbackValueGet([this]() { return _sz; }); szpc.setCallbackValueSet([this](QSize v, QtnPropertyChangeReason /*reason*/) { _sz = v; }); szpc.setId(31); static QString ep_name = QStringLiteral("ep"); ep.setName(ep_name); ep.setEnumInfo(&COLOR::info()); ep.setId(32); ep.setValue(COLOR::BLUE); static QString epc_name = QStringLiteral("epc"); epc.setName(epc_name); epc.setCallbackValueGet([this]() { return _e; }); epc.setCallbackValueSet([this](QtnEnumValueType v, QtnPropertyChangeReason /*reason*/) { _e = v; }); epc.setEnumInfo(&COLOR::info()); epc.setId(33); static QString efp_name = QStringLiteral("efp"); efp.setName(efp_name); efp.setEnumInfo(&MASK::info()); efp.setId(34); efp.setValue(MASK::ONE|MASK::FOUR); static QString efpc_name = QStringLiteral("efpc"); efpc.setName(efpc_name); efpc.setCallbackValueGet([this]() { return _ef; }); efpc.setCallbackValueSet([this](QtnEnumFlagsValueType v, QtnPropertyChangeReason /*reason*/) { _ef = v; }); efpc.setEnumInfo(&MASK::info()); efpc.setId(35); static QString cp_name = QStringLiteral("cp"); cp.setName(cp_name); cp.setId(36); cp.setValue(QColor(Qt::blue)); static QString cpc_name = QStringLiteral("cpc"); cpc.setName(cpc_name); cpc.setCallbackValueGet([this]() { return _cl; }); cpc.setCallbackValueSet([this](QColor v, QtnPropertyChangeReason /*reason*/) { _cl = v; }); cpc.setId(37); static QString fnp_name = QStringLiteral("fnp"); fnp.setName(fnp_name); fnp.setId(38); fnp.setValue(QFont("Courier", 10)); static QString fnpc_name = QStringLiteral("fnpc"); fnpc.setName(fnpc_name); fnpc.setCallbackValueGet([this]() { return _fn; }); fnpc.setCallbackValueSet([this](QFont v, QtnPropertyChangeReason /*reason*/) { _fn = v; }); fnpc.setId(39); static QString bttn_name = QStringLiteral("bttn"); bttn.setName(bttn_name); bttn.setId(40); static QString ppf_name = QStringLiteral("ppf"); ppf.setName(ppf_name); ppf.setId(41); static QString ppfc_name = QStringLiteral("ppfc"); ppfc.setName(ppfc_name); ppfc.setCallbackValueGet([this]() { return _pf; }); ppfc.setCallbackValueSet([this](QPointF v, QtnPropertyChangeReason /*reason*/) { _pf = v; }); ppfc.setId(42); static QString rpf_name = QStringLiteral("rpf"); rpf.setName(rpf_name); rpf.setId(43); static QString rpfc_name = QStringLiteral("rpfc"); rpfc.setName(rpfc_name); rpfc.setCallbackValueGet([this]() { return _rf; }); rpfc.setCallbackValueSet([this](QRectF v, QtnPropertyChangeReason /*reason*/) { _rf = v; }); rpfc.setId(44); static QString szpf_name = QStringLiteral("szpf"); szpf.setName(szpf_name); szpf.setId(45); static QString szpfc_name = QStringLiteral("szpfc"); szpfc.setName(szpfc_name); szpfc.setCallbackValueGet([this]() { return _szf; }); szpfc.setCallbackValueSet([this](QSizeF v, QtnPropertyChangeReason /*reason*/) { _szf = v; }); szpfc.setId(46); // end children initialization } void QtnPropertySetAllPropertyTypes::connectSlots() { } void QtnPropertySetAllPropertyTypes::disconnectSlots() { } void QtnPropertySetAllPropertyTypes::connectDelegates() { } static QtnEnumInfo& create_MY_TYPE_info() { QVector staticValues; staticValues.append(QtnEnumValueInfo(MY_TYPE::MY_TYPE1, "MY_TYPE1", "My type 1")); staticValues.append(QtnEnumValueInfo(MY_TYPE::MY_TYPE2, "MY_TYPE2", "My type 2")); static QtnEnumInfo enumInfo("MY_TYPE", staticValues); return enumInfo; } const QtnEnumInfo& MY_TYPE::info() { static QtnEnumInfo& enumInfo = create_MY_TYPE_info(); return enumInfo; } QtnPropertySetTest12::QtnPropertySetTest12(QObject* parent) : QtnPropertySet(parent) , p(*qtnCreateProperty(this)) { init(); connectSlots(); connectDelegates(); } QtnPropertySetTest12::~QtnPropertySetTest12() { disconnectSlots(); } QtnPropertySetTest12& QtnPropertySetTest12::operator=(const QtnPropertySetTest12& other) { Q_UNUSED(other); p = other.p; return *this; } QtnPropertySet* QtnPropertySetTest12::createNewImpl(QObject* parentForNew) const { return new QtnPropertySetTest12(parentForNew); } QtnPropertySet* QtnPropertySetTest12::createCopyImpl(QObject* parentForCopy) const { QtnPropertySetTest12* p = new QtnPropertySetTest12(parentForCopy); *p = *this; return p; } bool QtnPropertySetTest12::copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) { Q_UNUSED(ignoreMask); auto theCopyFrom = qobject_cast(propertySetCopyFrom); if (!theCopyFrom) return false; if (!(theCopyFrom->p.state() & ignoreMask)) { p = theCopyFrom->p; } return true; } void QtnPropertySetTest12::init() { static QString Test12_name = QStringLiteral("Test12"); setName(Test12_name); // start children initialization static QString p_name = QStringLiteral("p"); p.setName(p_name); p.setEnumInfo(&MY_TYPE::info()); p.setValue(MY_TYPE::MY_TYPE1); // end children initialization } void QtnPropertySetTest12::connectSlots() { } void QtnPropertySetTest12::disconnectSlots() { } void QtnPropertySetTest12::connectDelegates() { } ================================================ FILE: Tests/PEG/test.peg.h ================================================ #ifndef TEST_H #define TEST_H #include "QtnProperty/Enum.h" #include "QtnProperty/PropertyCore.h" #include "QtnProperty/PropertyGUI.h" class QtnPropertySetTest1: public QtnPropertySet { Q_OBJECT //Q_DISABLE_COPY(QtnPropertySetTest1) public: // constructor declaration explicit QtnPropertySetTest1(QObject* parent = nullptr); // destructor declaration virtual ~QtnPropertySetTest1() override; // assignment declaration QtnPropertySetTest1& operator=(const QtnPropertySetTest1& other); // start children declarations QtnPropertyInt& a; QtnPropertyQString& text; // end children declarations protected: // cloning implementation QtnPropertySet* createNewImpl(QObject* parentForNew) const override; QtnPropertySet* createCopyImpl(QObject* parentForCopy) const override; // copy values implementation bool copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) override; private: void init(); void connectSlots(); void disconnectSlots(); void connectDelegates(); }; class QtnPropertySetTest2: public QtnPropertySet { Q_OBJECT //Q_DISABLE_COPY(QtnPropertySetTest2) public: // constructor declaration explicit QtnPropertySetTest2(QObject* parent = nullptr); // destructor declaration virtual ~QtnPropertySetTest2() override; // assignment declaration QtnPropertySetTest2& operator=(const QtnPropertySetTest2& other); protected: // cloning implementation QtnPropertySet* createNewImpl(QObject* parentForNew) const override; QtnPropertySet* createCopyImpl(QObject* parentForCopy) const override; // copy values implementation bool copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) override; private: void init(); void connectSlots(); void disconnectSlots(); void connectDelegates(); }; // declaration void aaa(); class QtnPropertySetYY: public QtnPropertySet { Q_OBJECT //Q_DISABLE_COPY(QtnPropertySetYY) public: // constructor declaration explicit QtnPropertySetYY(QObject* parent = nullptr); // destructor declaration virtual ~QtnPropertySetYY() override; // assignment declaration QtnPropertySetYY& operator=(const QtnPropertySetYY& other); // start children declarations QtnPropertyQRect& rect; QtnPropertyQString& s; // end children declarations protected: // cloning implementation QtnPropertySet* createNewImpl(QObject* parentForNew) const override; QtnPropertySet* createCopyImpl(QObject* parentForCopy) const override; // copy values implementation bool copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) override; private: void init(); void connectSlots(); void disconnectSlots(); void connectDelegates(); }; class QtnPropertySetAA: public QtnPropertySet { Q_OBJECT //Q_DISABLE_COPY(QtnPropertySetAA) public: // constructor declaration explicit QtnPropertySetAA(QObject* parent = nullptr); // destructor declaration virtual ~QtnPropertySetAA() override; // assignment declaration QtnPropertySetAA& operator=(const QtnPropertySetAA& other); protected: // cloning implementation QtnPropertySet* createNewImpl(QObject* parentForNew) const override; QtnPropertySet* createCopyImpl(QObject* parentForCopy) const override; // copy values implementation bool copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) override; private: void init(); void connectSlots(); void disconnectSlots(); void connectDelegates(); private: bool m_s; }; class QtnPropertySetSS: public QtnPropertySet { Q_OBJECT //Q_DISABLE_COPY(QtnPropertySetSS) public: // constructor declaration explicit QtnPropertySetSS(QObject* parent = nullptr); // destructor declaration virtual ~QtnPropertySetSS() override; // assignment declaration QtnPropertySetSS& operator=(const QtnPropertySetSS& other); // start children declarations QtnPropertyBool& a; QtnPropertySetAA& aa; // end children declarations protected: // cloning implementation QtnPropertySet* createNewImpl(QObject* parentForNew) const override; QtnPropertySet* createCopyImpl(QObject* parentForCopy) const override; // copy values implementation bool copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) override; private: void init(); void connectSlots(); void disconnectSlots(); void connectDelegates(); }; class QtnPropertySetTest3: public QtnPropertySet { Q_OBJECT //Q_DISABLE_COPY(QtnPropertySetTest3) public: // constructor declaration explicit QtnPropertySetTest3(QObject* parent = nullptr); // destructor declaration virtual ~QtnPropertySetTest3() override; // assignment declaration QtnPropertySetTest3& operator=(const QtnPropertySetTest3& other); // start children declarations QtnPropertySetYY& yy; QtnPropertySetSS& iis; QtnPropertyBool& u; QtnPropertySetTest2& xx; QtnPropertySetTest2& tt; QtnPropertySetSS& s; QtnPropertyBool& ww; QtnPropertyBoolCallback& bc; // end children declarations protected: // cloning implementation QtnPropertySet* createNewImpl(QObject* parentForNew) const override; QtnPropertySet* createCopyImpl(QObject* parentForCopy) const override; // copy values implementation bool copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) override; private: void init(); void connectSlots(); void disconnectSlots(); void connectDelegates(); // start slot declarations void on_propertyDidChange(QtnPropertyChangeReason reason); void on_u_propertyWillChange(QtnPropertyChangeReason reason, QtnPropertyValuePtr newValue, int typeId); void on_u_propertyDidChange(QtnPropertyChangeReason reason); void on_s_a_propertyValueAccept(QtnPropertyValuePtr valueToAccept, bool* accept); void on_s_a_propertyWillChange(QtnPropertyChangeReason reason, QtnPropertyValuePtr newValue, int typeId); // end slot declarations public: bool m_s; }; class LANGUAGE { public: enum Enum { ENG = 3 }; static const QtnEnumInfo& info(); static const unsigned int values_count = 1; }; class TYPE { public: static const QtnEnumInfo& info(); static const unsigned int values_count = 0; }; class COLOR { public: enum Enum { RED = 10, BLUE = 22, YELLOW = 1 }; static const QtnEnumInfo& info(); static const unsigned int values_count = 3; }; class MASK { public: enum Enum { ONE = 1, TWO = 2, FOUR = 4 }; static const QtnEnumInfo& info(); static const unsigned int values_count = 3; }; class QtnPropertySetAllPropertyTypes: public QtnPropertySet { Q_OBJECT //Q_DISABLE_COPY(QtnPropertySetAllPropertyTypes) public: // constructor declaration explicit QtnPropertySetAllPropertyTypes(QObject* parent = nullptr); // destructor declaration virtual ~QtnPropertySetAllPropertyTypes() override; // assignment declaration QtnPropertySetAllPropertyTypes& operator=(const QtnPropertySetAllPropertyTypes& other); // start children declarations QtnPropertyBool& bp; QtnPropertyBoolCallback& bpc; QtnPropertyInt& ip; QtnPropertyIntCallback& ipc; QtnPropertyUInt& up; QtnPropertyUIntCallback& upc; QtnPropertyFloat& fp; QtnPropertyFloatCallback& fpc; QtnPropertyDouble& dp; QtnPropertyDoubleCallback& dpc; QtnPropertyQString& sp; QtnPropertyQStringCallback& spc; QtnPropertyQRect& rp; QtnPropertyQRectCallback& rpc; QtnPropertyQPoint& pp; QtnPropertyQPointCallback& ppc; QtnPropertyQSize& szp; QtnPropertyQSizeCallback& szpc; QtnPropertyEnum& ep; QtnPropertyEnumCallback& epc; QtnPropertyEnumFlags& efp; QtnPropertyEnumFlagsCallback& efpc; QtnPropertyQColor& cp; QtnPropertyQColorCallback& cpc; QtnPropertyQFont& fnp; QtnPropertyQFontCallback& fnpc; QtnPropertyButton& bttn; QtnPropertyQPointF& ppf; QtnPropertyQPointFCallback& ppfc; QtnPropertyQRectF& rpf; QtnPropertyQRectFCallback& rpfc; QtnPropertyQSizeF& szpf; QtnPropertyQSizeFCallback& szpfc; // end children declarations protected: // cloning implementation QtnPropertySet* createNewImpl(QObject* parentForNew) const override; QtnPropertySet* createCopyImpl(QObject* parentForCopy) const override; // copy values implementation bool copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) override; private: void init(); void connectSlots(); void disconnectSlots(); void connectDelegates(); private: bool _b; qint32 _i; quint32 _ui; float _f; double _d; QString _s; QRect _r; QRectF _rf; QPoint _p; QPointF _pf; QSize _sz; QSizeF _szf; QtnEnumValueType _e; QtnEnumFlagsValueType _ef; QColor _cl; QFont _fn; }; class MY_TYPE { public: enum Enum { MY_TYPE1 = 1, MY_TYPE2 = 2 }; static const QtnEnumInfo& info(); static const unsigned int values_count = 2; }; class QtnPropertySetTest12: public QtnPropertySet { Q_OBJECT //Q_DISABLE_COPY(QtnPropertySetTest12) public: // constructor declaration explicit QtnPropertySetTest12(QObject* parent = nullptr); // destructor declaration virtual ~QtnPropertySetTest12() override; // assignment declaration QtnPropertySetTest12& operator=(const QtnPropertySetTest12& other); // start children declarations QtnPropertyEnum& p; // end children declarations protected: // cloning implementation QtnPropertySet* createNewImpl(QObject* parentForNew) const override; QtnPropertySet* createCopyImpl(QObject* parentForCopy) const override; // copy values implementation bool copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) override; private: void init(); void connectSlots(); void disconnectSlots(); void connectDelegates(); }; #endif // TEST_H ================================================ FILE: Tests/PEG/test2.pef ================================================ #include_h "QtnProperty/PropertyCore.h" property_set A { id = 50; Bool b { id = 51; value = true; description = "b property"; delegate Combobox { labelTrue = "On"; labelFalse = "Off"; } } code_h { public: void setOwner(int a); } code_cpp { void QtnPropertySetA::setOwner(int a) { b = (bool)a; } } }; ================================================ FILE: Tests/PEG/test2.peg.cpp ================================================ #include "test2.peg.h" QtnPropertySetA::QtnPropertySetA(QObject* parent) : QtnPropertySet(parent) , b(*qtnCreateProperty(this)) { init(); connectSlots(); connectDelegates(); } QtnPropertySetA::~QtnPropertySetA() { disconnectSlots(); } QtnPropertySetA& QtnPropertySetA::operator=(const QtnPropertySetA& other) { Q_UNUSED(other); b = other.b; return *this; } QtnPropertySet* QtnPropertySetA::createNewImpl(QObject* parentForNew) const { return new QtnPropertySetA(parentForNew); } QtnPropertySet* QtnPropertySetA::createCopyImpl(QObject* parentForCopy) const { QtnPropertySetA* p = new QtnPropertySetA(parentForCopy); *p = *this; return p; } bool QtnPropertySetA::copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) { Q_UNUSED(ignoreMask); auto theCopyFrom = qobject_cast(propertySetCopyFrom); if (!theCopyFrom) return false; if (!(theCopyFrom->b.state() & ignoreMask)) { b = theCopyFrom->b; } return true; } void QtnPropertySetA::init() { static QString A_name = QStringLiteral("A"); setName(A_name); setId(50); // start children initialization static QString b_name = QStringLiteral("b"); b.setName(b_name); static QString b_description = "b property"; b.setDescription(b_description); b.setId(51); b.setValue(true); // end children initialization } void QtnPropertySetA::connectSlots() { } void QtnPropertySetA::disconnectSlots() { } void QtnPropertySetA::connectDelegates() { b.setDelegateInfoCallback([] () -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "Combobox"; info.attributes["labelFalse"] = "Off"; info.attributes["labelTrue"] = "On"; return info; }); } void QtnPropertySetA::setOwner(int a) { b = (bool)a; } ================================================ FILE: Tests/PEG/test2.peg.h ================================================ #ifndef TEST2_H #define TEST2_H #include "QtnProperty/PropertyCore.h" class QtnPropertySetA: public QtnPropertySet { Q_OBJECT //Q_DISABLE_COPY(QtnPropertySetA) public: // constructor declaration explicit QtnPropertySetA(QObject* parent = nullptr); // destructor declaration virtual ~QtnPropertySetA() override; // assignment declaration QtnPropertySetA& operator=(const QtnPropertySetA& other); // start children declarations QtnPropertyBool& b; // end children declarations protected: // cloning implementation QtnPropertySet* createNewImpl(QObject* parentForNew) const override; QtnPropertySet* createCopyImpl(QObject* parentForCopy) const override; // copy values implementation bool copyValuesImpl(QtnPropertySet* propertySetCopyFrom, QtnPropertyState ignoreMask) override; private: void init(); void connectSlots(); void disconnectSlots(); void connectDelegates(); public: void setOwner(int a); }; #endif // TEST2_H ================================================ FILE: Tests/TestEnum.cpp ================================================ #include "TestEnum.h" #include "PEG/test.peg.h" #include void TestEnum::enumValue() { COLOR::Enum color = COLOR::RED; QVERIFY(color == COLOR::RED); } void TestEnum::forEachEnumValue() { unsigned int count = 0; COLOR::info().forEachEnumValue([&count](const QtnEnumValueInfo&)->bool { ++count; return true; }); QVERIFY(count == COLOR::values_count); } void TestEnum::find() { QVERIFY(COLOR::info().findByValue(COLOR::RED)); QVERIFY(!COLOR::info().findByValue(333)); QVERIFY(COLOR::info().findByDisplayName("Blue")); QVERIFY(COLOR::info().findByName("BLUE")); QVERIFY(!COLOR::info().findByName("Brown")); QVERIFY(!COLOR::info().findByDisplayName("Brown")); } void TestEnum::state() { QVERIFY(COLOR::info().findByValue(COLOR::RED)->state() == QtnEnumValueStateNone); QVERIFY(COLOR::info().findByValue(COLOR::BLUE)->state() == (QtnEnumValueStateHidden | QtnEnumValueStateObsolete)); } ================================================ FILE: Tests/TestEnum.h ================================================ #ifndef TEST_ENUM_H #define TEST_ENUM_H /* #include "Property.h" #include "Enum.h" #include "PropertyCore.h" #include "PEG/test.peg.h" #include */ #include class TestEnum: public QObject { Q_OBJECT public: Q_INVOKABLE TestEnum() {} private Q_SLOTS: void enumValue(); void forEachEnumValue(); void find(); void state(); }; #endif // TEST_ENUM_H ================================================ FILE: Tests/TestGeneratedProperty.cpp ================================================ #include "TestGeneratedProperty.h" #include "PEG/test.peg.h" #include "PEG/test2.peg.h" #include void TestGeneratedProperty::test1() { QtnPropertySetTest1 p; QVERIFY(p.name() == "Test1"); p.a = 2; QVERIFY(p.a == 2); p.a = 15; QVERIFY(p.a.maxValue() == 10); QVERIFY(p.a == 2); p.a.incrementValue(); QVERIFY(p.a == 1); QVERIFY(p.a > 0 && p.a >= 0 && p.a < 2 && p.a <= 1 && p.a != 3); QVERIFY(p.text == "#^{};"); QVERIFY(p.text.description() == "defrf\"sde\"" "deerf3rfderf r g\r\nreg r{}dfrgergfwrewre"); p.text = QString("new value"); QVERIFY(p.text == "new value"); } void TestGeneratedProperty::test2() { QtnPropertySetTest3 n(this); n.setName("SS"); QVERIFY(n.name() == "SS"); QVERIFY(n.yy.rect == QRect(10, 10, 10, 10)); QVERIFY(!n.s.a); n.s.a = true; QVERIFY(n.s.a); QVERIFY(n.yy.rect == QRect(1, 1, 1, 1)); QVERIFY(n.ww == n.bc && n.bc == false); n.ww = true; QVERIFY(n.ww == n.bc && n.ww == true); n.bc = false; QVERIFY(n.bc); n.m_s = false; n.bc = true; QVERIFY(n.m_s); } void TestGeneratedProperty::testAllPropertyTypes() { QtnPropertySetAllPropertyTypes p; QVERIFY(p.ep == COLOR::BLUE); p.ep = COLOR::RED; switch (p.ep) { case COLOR::BLUE: case COLOR::YELLOW: QFAIL("ep expected as COLOR::RED"); break; case COLOR::RED: break; default: QFAIL("ep expected as COLOR::RED"); } } void TestGeneratedProperty::testLoadSave() { { QtnPropertySetAllPropertyTypes p; QtnPropertySetA p2; { QtnPropertySet allProperties(nullptr); allProperties.addChildProperty(&p, false); allProperties.addChildProperty(&p2, false); QByteArray data; { QDataStream s(&data, QIODevice::WriteOnly); s.setVersion(QDataStream::Qt_4_2); QVERIFY(allProperties.save(s)); } QCOMPARE(data.toBase64(), QByteArray( "GYQCAAAEWwACAAAAAAAAAAACAAAADRmEAgAABBEAAgAAAAAAAAAAAgAAAA" "4ZhAIAAAALAAIAAAAAAAAAAAAAAAAPGYQCAAAACwACAAAAAAAAAAABAAAA" "EBmEAgAAAA4AAgAAAQAAAAAAAAAAAAAAABEZhAIAAAAOAAIAAAAAAAAAAA" "AAAAwAAAASGYQCAAAADgACAAABAAAAAAAAAAAAAAAAExmEAgAAAA4AAgAA" "AAAAAAAAAAAACQAAABQZhAIAAAAOAAIAAAEAAAAAAAAAAAAAAAAVGYQCAA" "AADgACAAAAAAAAAAA+" "TMzNAAAAFhmEAgAAABIAAgAAAQAAAAAAAAAAAAAAAAAAAAAXGYQCAAAAEg" "ACAAAAAAAAAABAQDMzMzMzMwAAABgZhAIAAAAOAAIAAAAAAAAAAP////" "8AAAAZGYQCAAAAFgACAAAAAAAAAAAAAAAIAG4AYQBtAGUAAAAaGYQCAAAA" "GgACAAAAAAAAAAAAAAAAAAAAAP//////////" "AAAAGxmEAgAAABoAAgAAAAAAAAAAAAAACgAAAAoAAAATAAAAEwAAABwZhA" "IAAAASAAIAAAAAAAAAAAAAAAAAAAAAAAAAHRmEAgAAABIAAgAAAAAAAAAA" "AAAACQAAAAIAAAAeGYQCAAAAEgACAAAAAAAAAAD//////////" "wAAAB8ZhAIAAAASAAIAAAAAAAAAAAAAACEAAAAVAAAAIBmEAgAAAA4AAgA" "AAAAAAAAAAAAAFgAAACEZhAIAAAAOAAIAAAAAAAAAAAAAAAoAAAAiGYQCA" "AAADgACAAAAAAAAAAAAAAAFAAAAIxmEAgAAAA4AAgAAAAAAAAAAAAAABQA" "AACQZhAIAAAAVAAIAAAAAAAAAAAH//wAAAAD//" "wAAAAAAJRmEAgAAABUAAgAAAAAAAAAAAf////" "8AAAAAAAAAAAAmGYQCAAAALQACAAAAAAAAAAAAAAAOAEMAbwB1AHIAaQBl" "AHJAJAAAAAAAAP////" "8FAQAyEAAAACcZhAIAAAApAAIAAAAAAAAAAAAAAAoAQQByAGkAYQBsQDMA" "AAAAAAD/////" "BQEAMhAAAAApGYQCAAAAGgACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAKhmEAgAAABoAAgAAAAAAAAAAQCPMzMzMzM1AAZmZmZmZmgAAACsZhAIA" "AAAqAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAALBmEAgAAACoAAgAAAAAAAAAAQCQzMzMzMzNAJGZmZmZmZkAkmZmZ" "mZmaQCTMzMzMzM0AAAAtGYQCAAAAGgACAAAAAAAAAAC/8AAAAAAAAL/" "wAAAAAAAAAAAALhmEAgAAABoAAgAAAAAAAAAAQECAAAAAAABANeZmZmZmZ" "v////" "8AAAAyGYQCAAAAJQACAAAAAAAAAAACAAAAMxmEAgAAAAsAAgAAAAAAAAAA" "Af//////////")); QCOMPARE(data.size(), 1122); { QDataStream s(&data, QIODevice::ReadOnly); s.setVersion(QDataStream::Qt_4_2); QVERIFY(allProperties.load(s)); } QString result; QVERIFY(allProperties.toStr(result)); QCOMPARE(result.size(), 1091); } } } void TestGeneratedProperty::testJson() { QtnPropertySetAllPropertyTypes p; QJsonObject o; QVERIFY(p.toJson(o)); QJsonDocument d(o); auto res = d.toJson(); QCOMPARE(res.size(), 1595); res = d.toJson(QJsonDocument::Compact); QCOMPARE(res.size(), 921); QVERIFY(p.fromJson(o)); } ================================================ FILE: Tests/TestGeneratedProperty.h ================================================ #ifndef TEST_GENERATED_PROPERTY_H #define TEST_GENERATED_PROPERTY_H #include class TestGeneratedProperty: public QObject { Q_OBJECT public: Q_INVOKABLE TestGeneratedProperty() {} private Q_SLOTS: void test1(); void test2(); void testAllPropertyTypes(); void testLoadSave(); void testJson(); }; #endif // TEST_GENERATED_PROPERTY_H ================================================ FILE: Tests/TestProperty.cpp ================================================ #include "TestProperty.h" #include "QtnProperty/QObjectPropertySet.h" #include "PEG/test.peg.h" #include #include static bool ret_true() { return true; } static void verifyInitialValues(QtnPropertySetAllPropertyTypes &pp) { QVERIFY(pp.bp == false); QVERIFY(pp.bpc == true); QVERIFY(pp.ip == 0); QVERIFY(pp.ipc == 12); QVERIFY(pp.up == 0u); QVERIFY(pp.upc == 9u); QVERIFY(pp.fp == 0.f); QVERIFY(pp.fpc == 0.2f); QVERIFY(pp.dp == 0.); QVERIFY(pp.dpc == 32.4); QVERIFY(pp.sp == ""); QVERIFY(pp.spc == "name"); QVERIFY(pp.rp == QRect()); QVERIFY(pp.rpc == QRect(10, 10, 10, 10)); QVERIFY(pp.rpf == QRectF()); QVERIFY(pp.rpfc == QRectF(10.1, 10.2, 10.3, 10.4)); QVERIFY(pp.pp == QPoint()); QVERIFY(pp.ppc == QPoint(9, 2)); QVERIFY(pp.ppf == QPointF()); QVERIFY(pp.ppfc == QPointF(9.9, 2.2)); QVERIFY(pp.szp == QSize()); QVERIFY(pp.szpc == QSize(33, 21)); QVERIFY(pp.szpf == QSizeF()); QVERIFY(pp.szpfc == QSizeF(33.0, 21.9)); QVERIFY(pp.ep == COLOR::BLUE); QVERIFY(pp.epc == COLOR::RED); QVERIFY(pp.efp == (MASK::ONE | MASK::FOUR)); QVERIFY(pp.efpc == (MASK::ONE | MASK::FOUR)); QVERIFY(pp.cp == QColor(Qt::blue)); QVERIFY(pp.cpc == QColor(Qt::red)); QVERIFY(pp.fnp == QFont("Courier", 10)); QVERIFY(pp.fnpc == QFont("Arial", 19)); } static void modify(QtnPropertySetAllPropertyTypes &pp) { pp.bp = true; pp.bpc = false; pp.ip = 12; pp.ipc = 2; pp.up = 3u; pp.upc = 32u; pp.fp = 0.32f; pp.fpc = 32.2f; pp.dp = 12.; pp.dpc = 2.4; pp.sp = "test"; pp.spc = "name#1"; pp.rp = QRect(12, 10, 16, 17); pp.rpc = QRect(4, 3, 1, 0); pp.rpf = QRectF(12.3, 10.4, 16.5, 17.6); pp.rpfc = QRectF(4.1, 3.2, 1.3, 0.0); pp.pp = QPoint(21, 9); pp.ppc = QPoint(15, 0); pp.ppf = QPointF(21.21, 9.9); pp.ppfc = QPointF(15.15, 0.0); pp.szp = QSize(90, 87); pp.szpc = QSize(0, 1); pp.szpf = QSizeF(90.9, 87.7); pp.szpfc = QSizeF(0.1, 1.0); pp.ep = COLOR::RED; pp.epc = COLOR::BLUE; pp.efp = (MASK::FOUR); pp.efpc = (MASK::ONE); pp.cp = QColor(Qt::red); pp.cpc = QColor(Qt::blue); pp.fnp = QFont("Courier New", 11); pp.fnpc = QFont("Myfont", 0); } static void verifyModified(QtnPropertySetAllPropertyTypes &pp) { QCOMPARE(pp.bp.value(), true); QCOMPARE(pp.bpc.value(), false); QCOMPARE(pp.ip.value(), 12); QCOMPARE(pp.ipc.value(), 2); QCOMPARE(pp.up.value(), 3u); QCOMPARE(pp.upc.value(), 32u); QCOMPARE(pp.fp.value(), 0.32f); QCOMPARE(pp.fpc.value(), 32.2f); QCOMPARE(pp.dp.value(), 12.); QCOMPARE(pp.dpc.value(), 2.4); QCOMPARE(pp.sp.value(), QString("test")); QCOMPARE(pp.spc.value(), QString("name#1")); QCOMPARE(pp.rp.value(), QRect(12, 10, 16, 17)); QCOMPARE(pp.rpc.value(), QRect(4, 3, 1, 0)); QCOMPARE(pp.rpf.value(), QRectF(12.3, 10.4, 16.5, 17.6)); QCOMPARE(pp.rpfc.value(), QRectF(4.1, 3.2, 1.3, 0.0)); QCOMPARE(pp.pp.value(), QPoint(21, 9)); QCOMPARE(pp.ppc.value(), QPoint(15, 0)); QCOMPARE(pp.ppf.value(), QPointF(21.21, 9.9)); QCOMPARE(pp.ppfc.value(), QPointF(15.15, 0.0)); QCOMPARE(pp.szp.value(), QSize(90, 87)); QCOMPARE(pp.szpc.value(), QSize(0, 1)); QCOMPARE(pp.szpf.value(), QSizeF(90.9, 87.7)); QCOMPARE(pp.szpfc.value(), QSizeF(0.1, 1.0)); QCOMPARE(pp.ep.value(), (QtnEnumValueType) COLOR::RED); QCOMPARE(pp.epc.value(), (QtnEnumValueType) COLOR::BLUE); QCOMPARE(pp.efp.value(), (QtnEnumFlagsValueType) MASK::FOUR); QCOMPARE(pp.efpc.value(), (QtnEnumFlagsValueType) MASK::ONE); QCOMPARE(pp.cp.value(), QColor(Qt::red)); QCOMPARE(pp.cpc.value(), QColor(Qt::blue)); QCOMPARE(pp.fnp.value(), QFont("Courier New", 11)); QCOMPARE(pp.fnpc.value(), QFont("Myfont", 0)); } void TestProperty::name() { QtnPropertyInt p(this); p.setName(QString("PropertyName")); QCOMPARE(p.name(), QString("PropertyName")); QtnPropertySet p1(nullptr); p1.setName("AnotherName"); QCOMPARE(p1.name(), QString("AnotherName")); } void TestProperty::description() { QtnPropertyBool p(this); p.setDescription(QString("PropertyDescription")); QCOMPARE(p.description(), QString("PropertyDescription")); QtnPropertySet p1(nullptr); p1.setDescription("Another description\nwith multiline."); QCOMPARE(p1.description(), QString("Another description\nwith multiline.")); } void TestProperty::id() { QtnPropertySet p(nullptr); QCOMPARE(p.id(), QtnPropertyIDInvalid); p.setId(12); QCOMPARE(p.id(), 12); QtnPropertyUInt p1(&p); QCOMPARE(p1.id(), QtnPropertyIDInvalid); p1.setId(5); QCOMPARE(p1.id(), 5); } void TestProperty::state() { QtnPropertySet ps(0); QtnPropertyInt p(&ps); ps.addChildProperty(&p); QCOMPARE(ps.state(), QtnPropertyStateNone); QCOMPARE(p.state(), QtnPropertyStateResettable); QtnPropertyState master_state = QtnPropertyStateInvisible | QtnPropertyStateNonSimple; ps.setState(master_state); QCOMPARE(ps.state(), master_state); QCOMPARE(ps.stateLocal(), master_state); QCOMPARE(ps.stateInherited(), QtnPropertyStateNone); QCOMPARE(p.state(), master_state | QtnPropertyStateResettable); QCOMPARE(p.stateLocal(), QtnPropertyStateResettable); QCOMPARE(p.stateInherited(), master_state); p.addState(QtnPropertyStateImmutable); QCOMPARE(ps.state(), master_state); QCOMPARE(ps.stateLocal(), master_state); QCOMPARE(ps.stateInherited(), QtnPropertyStateNone); QCOMPARE(p.state(), master_state | QtnPropertyStateResettable | QtnPropertyStateImmutable); QCOMPARE( p.stateLocal(), QtnPropertyStateResettable | QtnPropertyStateImmutable); QCOMPARE(p.stateInherited(), master_state); ps.removeState(QtnPropertyStateInvisible); QCOMPARE(ps.state(), QtnPropertyStateNonSimple); QCOMPARE(ps.stateLocal(), QtnPropertyStateNonSimple); QCOMPARE(ps.stateInherited(), QtnPropertyStateNone); QCOMPARE(p.state(), QtnPropertyStateNonSimple | QtnPropertyStateResettable | QtnPropertyStateImmutable); QCOMPARE( p.stateLocal(), QtnPropertyStateResettable | QtnPropertyStateImmutable); QCOMPARE(p.stateInherited(), QtnPropertyStateNonSimple); p.switchState(QtnPropertyStateResettable, false); ps.switchState(QtnPropertyStateInvisible, true); QCOMPARE(ps.state(), master_state); QCOMPARE(ps.stateLocal(), master_state); QCOMPARE(ps.stateInherited(), QtnPropertyStateNone); QCOMPARE(p.state(), master_state | QtnPropertyStateImmutable); QCOMPARE(p.stateLocal(), QtnPropertyStateImmutable); QCOMPARE(p.stateInherited(), master_state); QVERIFY(!ps.isEditableByUser()); ps.removeState(master_state | QtnPropertyStateCollapsed); QVERIFY(ps.isEditableByUser()); QCOMPARE(ps.state(), QtnPropertyStateNone); int call_count = 0; auto connection1 = QObject::connect(&ps, &QtnPropertyBase::propertyWillChange, [&call_count](QtnPropertyChangeReason, QtnPropertyValuePtr, int) { ++call_count; }); auto connection2 = QObject::connect(&ps, &QtnPropertyBase::propertyDidChange, [&call_count](QtnPropertyChangeReason) { ++call_count; }); ps.addState(QtnPropertyStateNone, true); QCOMPARE(call_count, 2); ps.removeState(QtnPropertyStateCollapsed); QCOMPARE(call_count, 2); ps.removeState(QtnPropertyStateCollapsed, true); QCOMPARE(call_count, 4); QObject::disconnect(connection1); QObject::disconnect(connection2); } void TestProperty::stateChange() { QtnPropertyFloat p(this); QObject::connect(&p, &QtnPropertyBase::propertyWillChange, this, &TestProperty::checkPropertyStateIsNonSimple); p.addState(QtnPropertyStateNonSimple); } void TestProperty::propertyDelegate() { QtnPropertyBool p(this); QVERIFY(!p.delegateInfo()); QtnPropertyDelegateInfo info; info.name = "delegateName"; p.setDelegateInfo(info); QVERIFY(p.delegateInfo()); QVERIFY(p.delegateInfo()->name == "delegateName"); QVERIFY(p.delegateInfo()->attributes.isEmpty()); info.attributes["int"] = 4; p.setDelegateInfo(info); QVERIFY(p.delegateInfo()->attributes.size() == 1); QVERIFY(p.delegateInfo()->attributes["int"] == 4); info.attributes["str"] = QString("Text"); p.setDelegateInfo(info); QVERIFY(p.delegateInfo()->attributes.size() == 2); QVERIFY(p.delegateInfo()->attributes["str"] == "Text"); info.attributes["int"] = 12; p.setDelegateInfo(info); QVERIFY(p.delegateInfo()->attributes.size() == 2); QVERIFY(p.delegateInfo()->attributes["int"] == 12); } void TestProperty::propertyDelegateCallback() { QtnPropertyBool p(this); QVERIFY(!p.delegateInfo()); p.setDelegateInfoCallback([]() -> QtnPropertyDelegateInfo { QtnPropertyDelegateInfo info; info.name = "delegate"; info.attributes["one"] = 1; info.attributes["color"] = QColor(Qt::black); return info; }); QVERIFY(p.delegateInfo()); QVERIFY(p.delegateInfo()->name == "delegate"); QVERIFY(p.delegateInfo()->attributes.size() == 2); QVERIFY(p.delegateInfo()->attributes["one"] == 1); QVERIFY(p.delegateInfo()->attributes["color"] == QColor(Qt::black)); } void TestProperty::propertyBool() { { QtnPropertyBoolCallback p(this); p.setCallbackValueGet([]() -> bool { return false; }); QVERIFY(p.value() == false); p.setCallbackValueSet( [](bool newValue, QtnPropertyChangeReason /*reason*/) { QVERIFY(newValue == true); }); p = true; p.setCallbackValueSet( [](bool newValue, QtnPropertyChangeReason /*reason*/) { QVERIFY(newValue == false); }); p.setValue(false); QVERIFY2(!p, "p expected as false"); p.setCallbackValueGet(&ret_true); QVERIFY2(p, "p expected as true"); QtnPropertyBoolBase &p1 = p; QVERIFY2(p1, "p1 expected as true"); QtnPropertyBoolCallback p2(this); bool val = true; p2.setCallbackValueGet([&val]() -> bool { return val; }); p2.setCallbackValueSet( [&val](bool newValue, QtnPropertyChangeReason /*reason*/) { val = newValue; }); QVERIFY(p2); p2 = false; QVERIFY(!val); p2 = p; QVERIFY(p); p2 = !p; QVERIFY(!p2); p1 = p2; QVERIFY(p1 && p && !p2); QtnPropertyBool p3(this); p2 = p3 = true; QVERIFY(p2); } { QtnPropertyBool p(this); QVERIFY2(!p, "p expected as false"); p = true; QVERIFY(p == true); p = (p != true); QVERIFY(!p); switch (int(p) + 4) { case 4: break; default: QFAIL("p expected as false"); } p = bool(5); QVERIFY(p); QVERIFY(p != false); QVERIFY(p == true); QVERIFY(p && (p > false)); QVERIFY(p >= true); QVERIFY(!(p <= false)); QtnPropertyBoolCallback p2(this); p2.setCallbackValueGet([]() -> bool { return false; }); p = p2; QVERIFY(!p); } } void TestProperty::propertyInt() { QtnPropertyInt p(this); p.setMaxValue(10); p.setMinValue(1); p.setValue(5); QVERIFY(p.value() == 5); p.setMaxValue(3); QVERIFY(p.value() == 3); p = 1; QVERIFY(p == 1); QVERIFY(p > 0); QVERIFY(p >= 0); QVERIFY(p < 2); QVERIFY(p <= 2); } void TestProperty::propertyString() { QtnPropertyQString p(this); QVERIFY(p == QString("")); p = QString("hello"); QVERIFY(p == QString("hello")); p = "latin string"; QVERIFY(p == "latin string"); const QString &val = p; QVERIFY(val == "latin string"); } void TestProperty::propertyRect() { QtnPropertyQRect p(this); QVERIFY(p == QRect()); QRect rect(1, 2, 3, 4); p = rect; QVERIFY(p == rect); QtnPropertyQRectCallback pc(this); QRect pc_value; pc.setCallbackValueGet([&pc_value]() -> const QRect & { return pc_value; }); pc.setCallbackValueSet( [&pc_value](const QRect &value, QtnPropertyChangeReason /*reason*/) { pc_value = value; }); pc = QRect(10, 10, 10, 10); QCOMPARE(pc.value(), QRect(10, 10, 10, 10)); pc = p; QVERIFY(pc.value() == p.value()); QVERIFY(pc == p); QtnPropertyQRectBase *pb = &pc; *pb = QRect(3, 4, 5, 6); QVERIFY(pc.value() == pb->value() && (*pb) == QRect(3, 4, 5, 6)); } void TestProperty::propertyEnum() { QtnPropertyEnum p(this); p = COLOR::BLUE; QVERIFY(p != COLOR::BLUE); QVERIFY(!p.setValue(COLOR::RED)); p.setEnumInfo(&COLOR::info()); QVERIFY(p.setValue(COLOR::RED)); QVERIFY(p == COLOR::RED); QtnPropertyEnumCallback pc(this); pc.setCallbackValueGet([]() -> QtnEnumValueType { return COLOR::YELLOW; }); QVERIFY(pc == COLOR::YELLOW); } void TestProperty::propertyEnumFlags() { QtnPropertyEnumFlags p(this); p.setEnumInfo(&MASK::info()); p = MASK::ONE; //QVERIFY(p == MASK::ONE); p = MASK::TWO | MASK::FOUR; QVERIFY(p & MASK::FOUR); QVERIFY(!(p & MASK::ONE)); } void TestProperty::propertyPen() { { QtnPropertyQPenStyle p(this); p = Qt::SolidLine; QCOMPARE(p.value(), Qt::SolidLine); p = Qt::DashDotDotLine; QCOMPARE(p.value(), Qt::DashDotDotLine); } { QtnPropertyQPen p(this); { QPen pen(QBrush(QColor(10, 100, 200)), 10, Qt::DashDotLine, Qt::RoundCap, Qt::SvgMiterJoin); p = pen; QCOMPARE(p.value(), pen); } { QString str; QVERIFY(p.toStr(str)); QCOMPARE(str, QString("#0a64c8, DashDotLine, 10, RoundCap, " "SvgMiterJoin")); } { QString str = "#0000ff, DashLine, 3, SquareCap, BevelJoin"; QVERIFY(p.fromStr(str)); QCOMPARE(p.value().color(), QColor(Qt::blue)); QCOMPARE(p.value().width(), 3); QCOMPARE(p.value().style(), Qt::DashLine); QCOMPARE(p.value().capStyle(), Qt::SquareCap); QCOMPARE(p.value().joinStyle(), Qt::BevelJoin); } } } void TestProperty::propertyVector3D() { QVector3D testValue(12.f, 22.f, 33.f); QtnPropertyQVector3D p; p.setValue(testValue); QCOMPARE(p.value(), testValue); QString str; QVERIFY(p.toStr(str)); p.setValue(QVector3D(1.f, 1.f, 1.f)); QVERIFY(p.value() != testValue); QVERIFY(p.fromStr(str)); QCOMPARE(p.value(), testValue); } void TestProperty::propertySet() { QtnPropertySet p(this); QtnPropertySet pp(&p); pp.setName("pp"); p.addChildProperty(&pp); QtnPropertyBool b(&pp); b.setName("b"); pp.addChildProperty(&b); QtnPropertyFloat f(nullptr); f.setName("f"); p.addChildProperty(&f); QtnPropertyBool bb(&p); bb.setName("b"); p.addChildProperty(&bb); QList res = p.findChildProperties("pp"); QCOMPARE(res.size(), 1); QCOMPARE(res[0], &pp); res = p.findChildProperties("b"); QCOMPARE(res.size(), 2); res = p.findChildProperties("b", Qt::FindDirectChildrenOnly); QCOMPARE(res.size(), 1); QCOMPARE(res[0], &bb); res = pp.findChildProperties("b"); QCOMPARE(res.size(), 1); QCOMPARE(res[0], &b); res = p.findChildProperties("pp.b"); QCOMPARE(res.size(), 1); QCOMPARE(res[0], &b); } static void testSerializationState(QtnPropertyBase &p) { p.setState(QtnPropertyStateCollapsed); QByteArray data; { QDataStream s(&data, QIODevice::WriteOnly); QVERIFY(p.save(s)); } p.setState(QtnPropertyStateImmutable); QCOMPARE(p.state(), QtnPropertyStateImmutable); { QDataStream s(&data, QIODevice::ReadOnly); QVERIFY(p.load(s)); } QCOMPARE(p.state(), QtnPropertyStateCollapsed); } void TestProperty::serializationState() { { QtnPropertyInt p(this); testSerializationState(p); } { QtnPropertySet p(nullptr); testSerializationState(p); } } void TestProperty::serializationChildren() { QtnPropertySet ps(this); ps.setState(QtnPropertyStateCollapsed); QByteArray data; QtnProperty *p2(qtnCreateProperty(&ps)); p2->setId(1); p2->setState(QtnPropertyStateImmutable); QtnPropertyBool p3(&ps); p3.setId(2); p3.setState(QtnPropertyStateNonSerialized); ps.addChildProperty(&p3); { QDataStream s(&data, QIODevice::WriteOnly); s << ps; QCOMPARE(s.status(), QDataStream::Ok); } QCOMPARE( p2->state(), (QtnPropertyStateImmutable | QtnPropertyStateCollapsed)); QCOMPARE(p3.state(), (QtnPropertyStateNonSerialized | QtnPropertyStateCollapsed)); p2->removeState(QtnPropertyStateImmutable); p3.addState(QtnPropertyStateImmutable); QCOMPARE(p2->state(), QtnPropertyStateCollapsed); QCOMPARE(p3.state(), (QtnPropertyStateNonSerialized | QtnPropertyStateImmutable | QtnPropertyStateCollapsed)); { QDataStream s(&data, QIODevice::ReadOnly); s >> ps; QCOMPARE(s.status(), QDataStream::Ok); } QCOMPARE( p2->state(), (QtnPropertyStateImmutable | QtnPropertyStateCollapsed)); QCOMPARE(p3.state(), (QtnPropertyStateNonSerialized | QtnPropertyStateImmutable | QtnPropertyStateCollapsed)); delete p2; p2 = 0; { QDataStream s(&data, QIODevice::ReadOnly); s >> ps; QCOMPARE(s.status(), QDataStream::Ok); } } void TestProperty::serializationValue() { QtnPropertyBool p(this); p = true; QVERIFY(p); QByteArray data; { QDataStream s(&data, QIODevice::WriteOnly); s << p; QCOMPARE(s.status(), QDataStream::Ok); } p = false; QVERIFY(!p); { QDataStream s(&data, QIODevice::ReadOnly); s >> p; QCOMPARE(s.status(), QDataStream::Ok); } QVERIFY(p); QtnPropertySetAllPropertyTypes pp(this); verifyInitialValues(pp); { QDataStream s(&data, QIODevice::WriteOnly); s << pp; QCOMPARE(s.status(), QDataStream::Ok); } modify(pp); verifyModified(pp); { QDataStream s(&data, QIODevice::ReadWrite); s >> pp; QCOMPARE(s.status(), QDataStream::Ok); } verifyInitialValues(pp); } void TestProperty::createNew() { { QtnPropertySetAllPropertyTypes pp(this); verifyInitialValues(pp); modify(pp); QScopedPointer pn; pn.reset( qobject_cast(pp.createNew(this))); QVERIFY(pn); QVERIFY(pn.data() != &pp); QCOMPARE(pn->parent(), this); verifyInitialValues(*pn); } } void TestProperty::createCopy() { { QtnPropertySetAllPropertyTypes pp(this); verifyInitialValues(pp); modify(pp); QScopedPointer pn; pn.reset(qobject_cast( pp.createCopy(this))); QVERIFY(pn); QVERIFY(pn.data() != &pp); QCOMPARE(pn->parent(), this); verifyModified(*pn); } } void TestProperty::copyValues() { { QtnPropertySetAllPropertyTypes pp(this); verifyInitialValues(pp); modify(pp); QtnPropertySetAllPropertyTypes pp1(this); verifyInitialValues(pp1); pp1.copyValues(&pp, QtnPropertyStateNone); verifyModified(pp1); } { QtnPropertySetAllPropertyTypes pp(this); verifyInitialValues(pp); modify(pp); QtnPropertySetAllPropertyTypes pp1(this); verifyInitialValues(pp1); QCOMPARE(pp1.bp.value(), false); pp.bp.addState(QtnPropertyStateImmutable); QCOMPARE(pp.bp.state(), QtnPropertyStateImmutable); pp1.copyValues(&pp, QtnPropertyStateImmutable); QCOMPARE(pp1.bp.value(), false); pp1.copyValues(&pp); verifyModified(pp1); } } void TestProperty::propertyAssignment() { { QtnPropertyDouble p1(this); QtnPropertyDouble p2(this); QtnPropertyDoubleCallback p3(this); double d = 54.32; p1 = 0.5; p2 = 1.3; p3.setCallbackValueGet([]() -> double { return 23.4; }); p3.setCallbackValueSet( [&d](double v, QtnPropertyChangeReason /*reason*/) { d = v; }); QCOMPARE(p1.value(), 0.5); QCOMPARE(p2.value(), 1.3); QCOMPARE(p3.value(), 23.4); p2 = p1; QCOMPARE(p1.value(), 0.5); QCOMPARE(p2.value(), 0.5); p1 = p3; QCOMPARE(p3.value(), 23.4); QCOMPARE(p1.value(), 23.4); p3 = p2; QCOMPARE(p2.value(), 0.5); QCOMPARE(p3.value(), 23.4); QCOMPARE(d, 0.5); } { QtnPropertySetAllPropertyTypes pp(this); verifyInitialValues(pp); QtnPropertySetAllPropertyTypes pp1(this); verifyInitialValues(pp1); modify(pp); verifyModified(pp); pp1 = pp; verifyModified(pp1); } } void TestProperty::propertyScripting() { { QtnPropertyBool b(this); b.setName("isValid"); b.setDescription("isValid property."); b.setId(15); QScriptEngine eng; qtnScriptRegisterPropertyTypes(&eng); eng.globalObject().setProperty("b", eng.newQObject(&b)); QScriptValue val = eng.evaluate("b.name"); QCOMPARE(val.toString(), b.name()); val = eng.evaluate("b.name = \"a\""); QCOMPARE(b.name(), QString("isValid")); val = eng.evaluate("b.description"); QCOMPARE(val.toString(), QString("isValid property.")); val = eng.evaluate("b.description = 'new description'"); QCOMPARE(b.description(), QString("isValid property.")); val = eng.evaluate("var id = b.id"); val = eng.evaluate("id"); QVERIFY(val.isNumber()); QCOMPARE(val.toNumber(), 15.); val = eng.evaluate("b.id = 92"); QCOMPARE(b.id(), 15); val = eng.evaluate("b.isEditable"); QCOMPARE(val.toBool(), true); val = eng.evaluate("b.isEditable = false"); QCOMPARE(b.isEditableByUser(), true); b.addState(QtnPropertyStateImmutable); val = eng.evaluate("b.isEditable"); QCOMPARE(val.toBool(), false); b.setState(QtnPropertyStateInvisible); val = eng.evaluate("b.isEditable"); QCOMPARE(val.toBool(), true); val = eng.evaluate("b.isEditableByUser"); QCOMPARE(val.toBool(), false); val = eng.evaluate("b.state"); QCOMPARE(val.toUInt32(), 2u); val = eng.evaluate("b.state == QtnPropertyStateInvisible"); QCOMPARE(val.toBool(), true); val = eng.evaluate("b.state == QtnPropertyStateNonSerialized"); QCOMPARE(val.toBool(), false); val = eng.evaluate("b.value"); QCOMPARE(val.toBool(), false); b = true; val = eng.evaluate("b.value"); QCOMPARE(val.toBool(), true); val = eng.evaluate("b.value = false"); QCOMPARE(b.value(), false); eng.evaluate("b.state = 0"); QCOMPARE(b.state(), QtnPropertyStateInvisible); b.setState(QtnPropertyStateNone); val = eng.evaluate("b.value = false"); QCOMPARE(b.value(), false); eng.evaluate("var b_changed = false;" "function on_b_changed() {" " b_changed = true;" "}"); val = eng.evaluate("b_changed"); QCOMPARE(val.toBool(), false); val = eng.evaluate("on_b_changed()"); val = eng.evaluate("b_changed"); QCOMPARE(val.toBool(), true); eng.evaluate("var success = true;"); eng.evaluate( "var f1 = function(reason) {" " if (this.name != 'isValid') success = false;" " if (this.state != QtnPropertyStateNone) success = false;" " if (this.id != 15) success = false;" " if (reason != QtnPropertyChangeReasonNewValue) success = false;" " if (this.value != true) success = false;" "}"); eng.evaluate("b.propertyDidChange.connect(b, f1);"); eng.evaluate("b.value = true;"); val = eng.evaluate("success"); QCOMPARE(val.toBool(), true); eng.evaluate("b.propertyDidChange.disconnect(b, f1);"); eng.evaluate("b.value = true;"); val = eng.evaluate("success"); QCOMPARE(val.toBool(), true); } } void TestProperty::variantConversions() { { QtnPropertyBool b(this); QVariant value = true; QCOMPARE(b.value(), false); QVERIFY(b.fromVariant(value)); QCOMPARE(b.value(), true); value = QRect(); QVERIFY(!b.fromVariant(value)); QCOMPARE(b.value(), true); QVERIFY(b.toVariant(value)); QCOMPARE(value.toBool(), true); b = false; QVERIFY(b.toVariant(value)); QCOMPARE(value.toBool(), false); } { QtnPropertySetAllPropertyTypes pp(this); QVariant value; bool ok = false; QVERIFY(pp.bp.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::Bool); QCOMPARE(value.toBool(), false); value = true; QVERIFY(pp.bp.fromVariant(value)); QCOMPARE(pp.bp.value(), true); value = QPoint(3, 5); QVERIFY(!pp.bp.fromVariant(value)); QCOMPARE(pp.bp.value(), true); QVERIFY(pp.bpc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::Bool); QCOMPARE(value.toBool(), true); value = false; QVERIFY(pp.bpc.fromVariant(value)); QCOMPARE(pp.bpc.value(), false); value = QPoint(3, 5); QVERIFY(!pp.bpc.fromVariant(value)); QCOMPARE(pp.bpc.value(), false); QVERIFY(pp.ip.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::Int); QCOMPARE(value.toInt(&ok), 0); QVERIFY(ok); value = 13; QVERIFY(pp.ip.fromVariant(value)); QCOMPARE(pp.ip.value(), 13); value = QPoint(3, 5); QVERIFY(!pp.ip.fromVariant(value)); QCOMPARE(pp.ip.value(), 13); QVERIFY(pp.ipc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::Int); QCOMPARE(value.toInt(&ok), 12); QVERIFY(ok); value = -83; QVERIFY(pp.ipc.fromVariant(value)); QCOMPARE(pp.ipc.value(), -83); value = QPoint(3, 5); QVERIFY(!pp.ipc.fromVariant(value)); QCOMPARE(pp.ipc.value(), -83); QVERIFY(pp.up.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::UInt); QCOMPARE(value.toUInt(&ok), 0u); QVERIFY(ok); value = 98234; QVERIFY(pp.up.fromVariant(value)); QCOMPARE(pp.up.value(), 98234u); value = QPoint(3, 5); QVERIFY(!pp.up.fromVariant(value)); QCOMPARE(pp.up.value(), 98234u); QVERIFY(pp.upc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::UInt); QCOMPARE(value.toUInt(&ok), 9u); QVERIFY(ok); value = 76u; QVERIFY(pp.upc.fromVariant(value)); QCOMPARE(pp.upc.value(), 76u); value = QPoint(3, 5); QVERIFY(!pp.upc.fromVariant(value)); QCOMPARE(pp.upc.value(), 76u); QVERIFY(pp.fp.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::Float); QCOMPARE(value.toFloat(&ok), 0.f); QVERIFY(ok); value = 0.32f; QVERIFY(pp.fp.fromVariant(value)); QCOMPARE(pp.fp.value(), 0.32f); value = QPoint(3, 5); QVERIFY(!pp.fp.fromVariant(value)); QCOMPARE(pp.fp.value(), 0.32f); QVERIFY(pp.fpc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::Float); QCOMPARE(value.toFloat(&ok), 0.2f); QVERIFY(ok); value = -0.32f; QVERIFY(pp.fpc.fromVariant(value)); QCOMPARE(pp.fpc.value(), -0.32f); value = QPoint(3, 5); QVERIFY(!pp.fpc.fromVariant(value)); QCOMPARE(pp.fpc.value(), -0.32f); QVERIFY(pp.dp.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::Double); QCOMPARE(value.toDouble(&ok), 0.); QVERIFY(ok); value = -23.4; QVERIFY(pp.dp.fromVariant(value)); QCOMPARE(pp.dp.value(), -23.4); value = QPoint(3, 5); QVERIFY(!pp.dp.fromVariant(value)); QCOMPARE(pp.dp.value(), -23.4); QVERIFY(pp.dpc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::Double); QCOMPARE(value.toDouble(&ok), 32.4); QVERIFY(ok); value = 543.22; QVERIFY(pp.dpc.fromVariant(value)); QCOMPARE(pp.dpc.value(), 543.22); value = QPoint(3, 5); QVERIFY(!pp.dpc.fromVariant(value)); QCOMPARE(pp.dpc.value(), 543.22); pp.sp = QString("hello"); QVERIFY(pp.sp.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QString); QCOMPARE(value.toString(), QString("hello")); value = QString("world"); QVERIFY(pp.sp.fromVariant(value)); QCOMPARE(pp.sp.value(), QString("world")); value = QPoint(3, 5); QVERIFY(!pp.sp.fromVariant(value)); QCOMPARE(pp.sp.value(), QString("world")); QVERIFY(pp.spc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QString); QCOMPARE(value.toString(), QString("name")); value = QString("another"); QVERIFY(pp.spc.fromVariant(value)); QCOMPARE(pp.spc.value(), QString("another")); value = QPoint(3, 5); QVERIFY(!pp.spc.fromVariant(value)); QCOMPARE(pp.spc.value(), QString("another")); QVERIFY(pp.rp.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QRect); QCOMPARE(value.toRect(), QRect()); value = QRect(23, 4, 56, 76); QVERIFY(pp.rp.fromVariant(value)); QCOMPARE(pp.rp.value(), QRect(23, 4, 56, 76)); value = "sss"; QVERIFY(!pp.rp.fromVariant(value)); QCOMPARE(pp.rp.value(), QRect(23, 4, 56, 76)); QVERIFY(pp.rpc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QRect); QCOMPARE(value.toRect(), QRect(10, 10, 10, 10)); value = QRect(-2, 3, 23, 3); QVERIFY(pp.rpc.fromVariant(value)); QCOMPARE(pp.rpc.value(), QRect(-2, 3, 23, 3)); value = "sss"; QVERIFY(!pp.rpc.fromVariant(value)); QCOMPARE(pp.rpc.value(), QRect(-2, 3, 23, 3)); QVERIFY(pp.rpf.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QRectF); QCOMPARE(value.toRectF(), QRectF()); value = QRectF(23.1, 4.2, 56.3, 76.4); QVERIFY(pp.rpf.fromVariant(value)); QCOMPARE(pp.rpf.value(), QRectF(23.1, 4.2, 56.3, 76.4)); value = "sss"; QVERIFY(!pp.rpf.fromVariant(value)); QCOMPARE(pp.rpf.value(), QRectF(23.1, 4.2, 56.3, 76.4)); QVERIFY(pp.rpfc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QRectF); QCOMPARE(value.toRectF(), QRectF(10.1, 10.2, 10.3, 10.4)); value = QRectF(-2.7, 3.6, 23.5, 3.4); QVERIFY(pp.rpfc.fromVariant(value)); QCOMPARE(pp.rpfc.value(), QRectF(-2.7, 3.6, 23.5, 3.4)); value = "sss"; QVERIFY(!pp.rpfc.fromVariant(value)); QCOMPARE(pp.rpfc.value(), QRectF(-2.7, 3.6, 23.5, 3.4)); QVERIFY(pp.pp.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QPoint); QCOMPARE(value.toPoint(), QPoint()); value = QPoint(-2, 3); QVERIFY(pp.pp.fromVariant(value)); QCOMPARE(pp.pp.value(), QPoint(-2, 3)); value = "sss"; QVERIFY(!pp.pp.fromVariant(value)); QCOMPARE(pp.pp.value(), QPoint(-2, 3)); QVERIFY(pp.ppc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QPoint); QCOMPARE(value.toPoint(), QPoint(9, 2)); value = QPoint(100, 100); QVERIFY(pp.ppc.fromVariant(value)); QCOMPARE(pp.ppc.value(), QPoint(100, 100)); value = "sss"; QVERIFY(!pp.ppc.fromVariant(value)); QCOMPARE(pp.ppc.value(), QPoint(100, 100)); QVERIFY(pp.ppf.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QPointF); QCOMPARE(value.toPointF(), QPointF()); value = QPointF(-2.2, 3.3); QVERIFY(pp.ppf.fromVariant(value)); QCOMPARE(pp.ppf.value(), QPointF(-2.2, 3.3)); value = "sss"; QVERIFY(!pp.ppf.fromVariant(value)); QCOMPARE(pp.ppf.value(), QPointF(-2.2, 3.3)); QVERIFY(pp.ppfc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QPointF); QCOMPARE(value.toPointF(), QPointF(9.9, 2.2)); value = QPointF(100.100, 100.100); QVERIFY(pp.ppfc.fromVariant(value)); QCOMPARE(pp.ppfc.value(), QPointF(100.100, 100.100)); value = "sss"; QVERIFY(!pp.ppfc.fromVariant(value)); QCOMPARE(pp.ppfc.value(), QPointF(100.100, 100.100)); QVERIFY(pp.szp.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QSize); QCOMPARE(value.toSize(), QSize()); value = QSize(72, 3); QVERIFY(pp.szp.fromVariant(value)); QCOMPARE(pp.szp.value(), QSize(72, 3)); value = "sss"; QVERIFY(!pp.szp.fromVariant(value)); QCOMPARE(pp.szp.value(), QSize(72, 3)); QVERIFY(pp.szpc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QSize); QCOMPARE(value.toSize(), QSize(33, 21)); value = QSize(6, 4); QVERIFY(pp.szpc.fromVariant(value)); QCOMPARE(pp.szpc.value(), QSize(6, 4)); value = "sss"; QVERIFY(!pp.szpc.fromVariant(value)); QCOMPARE(pp.szpc.value(), QSize(6, 4)); QVERIFY(pp.szpf.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QSizeF); QCOMPARE(value.toSizeF(), QSizeF()); value = QSizeF(72.3, 3.2); QVERIFY(pp.szpf.fromVariant(value)); QCOMPARE(pp.szpf.value(), QSizeF(72.3, 3.2)); value = "sss"; QVERIFY(!pp.szpf.fromVariant(value)); QCOMPARE(pp.szpf.value(), QSizeF(72.3, 3.2)); QVERIFY(pp.szpfc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QSizeF); QCOMPARE(value.toSizeF(), QSizeF(33.0, 21.9)); value = QSizeF(6.3, 4.5); QVERIFY(pp.szpfc.fromVariant(value)); QCOMPARE(pp.szpfc.value(), QSizeF(6.3, 4.5)); value = "sss"; QVERIFY(!pp.szpfc.fromVariant(value)); QCOMPARE(pp.szpfc.value(), QSizeF(6.3, 4.5)); QVERIFY(pp.ep.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::Int); QCOMPARE(value.toInt(), (int) COLOR::BLUE); value = (int) COLOR::RED; QVERIFY(pp.ep.fromVariant(value)); QCOMPARE(pp.ep.value(), (int) COLOR::RED); value = QSize(6, 4); QVERIFY(!pp.ep.fromVariant(value)); QCOMPARE(pp.ep.value(), (int) COLOR::RED); QVERIFY(pp.epc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::Int); QCOMPARE(value.toInt(), (int) COLOR::RED); value = (int) COLOR::YELLOW; QVERIFY(pp.epc.fromVariant(value)); QCOMPARE(pp.epc.value(), (int) COLOR::YELLOW); value = QSize(6, 4); QVERIFY(!pp.epc.fromVariant(value)); QCOMPARE(pp.epc.value(), (int) COLOR::YELLOW); QVERIFY(pp.efp.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::Int); QCOMPARE(value.toInt(), (int) (MASK::ONE | MASK::FOUR)); value = (int) MASK::TWO; QVERIFY(pp.efp.fromVariant(value)); QCOMPARE(pp.efp.value(), (int) MASK::TWO); value = QSize(6, 4); QVERIFY(!pp.efp.fromVariant(value)); QCOMPARE(pp.efp.value(), (int) MASK::TWO); QVERIFY(pp.efpc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::Int); QCOMPARE(value.toInt(), (int) (MASK::ONE | MASK::FOUR)); value = (int) MASK::TWO; QVERIFY(pp.efpc.fromVariant(value)); QCOMPARE(pp.efpc.value(), (int) MASK::TWO); value = QSize(6, 4); QVERIFY(!pp.efpc.fromVariant(value)); QCOMPARE(pp.efpc.value(), (int) MASK::TWO); QVERIFY(pp.cp.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QColor); QCOMPARE(value.value(), QColor(Qt::blue)); value = QColor(200, 23, 44); QVERIFY(pp.cp.fromVariant(value)); QCOMPARE(pp.cp.value(), QColor(200, 23, 44)); value = QSize(6, 4); QVERIFY(!pp.cp.fromVariant(value)); QCOMPARE(pp.cp.value(), QColor(200, 23, 44)); QVERIFY(pp.cpc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QColor); QCOMPARE(value.value(), QColor(Qt::red)); value = QColor(0, 3, 3); QVERIFY(pp.cpc.fromVariant(value)); QCOMPARE(pp.cpc.value(), QColor(0, 3, 3)); value = QSize(6, 4); QVERIFY(!pp.cpc.fromVariant(value)); QCOMPARE(pp.cpc.value(), QColor(0, 3, 3)); QVERIFY(pp.fnp.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QFont); QCOMPARE(value.value(), QFont("Courier", 10)); value = QFont("Arial", 14); QVERIFY(pp.fnp.fromVariant(value)); QCOMPARE(pp.fnp.value(), QFont("Arial", 14)); value = QSize(6, 4); QVERIFY(!pp.fnp.fromVariant(value)); QCOMPARE(pp.fnp.value(), QFont("Arial", 14)); QVERIFY(pp.fnpc.toVariant(value)); QCOMPARE(value.userType(), (int) QMetaType::QFont); QCOMPARE(value.value(), QFont("Arial", 19)); value = QFont("Courier", 9); QVERIFY(pp.fnpc.fromVariant(value)); QCOMPARE(pp.fnpc.value(), QFont("Courier", 9)); value = QSize(6, 4); QVERIFY(!pp.fnpc.fromVariant(value)); QCOMPARE(pp.fnpc.value(), QFont("Courier", 9)); } } void TestProperty::stringConversions() { { QtnPropertyBool p(this); QString text; QVERIFY(p.toStr(text)); QCOMPARE(text, QString("False")); QVERIFY(p.fromStr("true")); QCOMPARE(p.value(), true); QVERIFY(p.toStr(text)); QCOMPARE(text, QString("True")); QVERIFY(!p.fromStr("Hello")); QCOMPARE(p.value(), true); } { QtnPropertySetAllPropertyTypes pp(this); QString str; // bool ok = false; QVERIFY(pp.bp.toStr(str)); QCOMPARE(str, QString("False")); QVERIFY(pp.bp.fromStr(QString("tRue"))); QCOMPARE(pp.bp.value(), true); QVERIFY(pp.bp.toStr(str)); QCOMPARE(str, QString("True")); QVERIFY(!pp.bp.fromStr("aaa")); QCOMPARE(pp.bp.value(), true); QVERIFY(pp.bpc.toStr(str)); QCOMPARE(str, QString("True")); QVERIFY(pp.bpc.fromStr(QString("falSe"))); QCOMPARE(pp.bpc.value(), false); QVERIFY(pp.bpc.toStr(str)); QCOMPARE(str, QString("False")); QVERIFY(!pp.bpc.fromStr("bbb")); QCOMPARE(pp.bpc.value(), false); QVERIFY(pp.ip.toStr(str)); QCOMPARE(str, QString("0")); QVERIFY(pp.ip.fromStr(QString("-23"))); QCOMPARE(pp.ip.value(), -23); QVERIFY(pp.ip.toStr(str)); QCOMPARE(str, QString("-23")); QVERIFY(!pp.ip.fromStr("93jms")); QCOMPARE(pp.ip.value(), -23); pp.ip.setMinValue(-2); QCOMPARE(pp.ip.value(), -2); QVERIFY(!pp.ip.fromStr("-32")); QCOMPARE(pp.ip.value(), -2); QVERIFY(pp.ipc.toStr(str)); QCOMPARE(str, QString("12")); QVERIFY(pp.ipc.fromStr(QString("45"))); QCOMPARE(pp.ipc.value(), 45); QVERIFY(pp.ipc.toStr(str)); QCOMPARE(str, QString("45")); QVERIFY(!pp.ipc.fromStr("23.22")); QCOMPARE(pp.ipc.value(), 45); QVERIFY(pp.up.toStr(str)); QCOMPARE(str, QString("0")); QVERIFY(pp.up.fromStr(QString("7829"))); QCOMPARE(pp.up.value(), 7829u); QVERIFY(pp.up.toStr(str)); QCOMPARE(str, QString("7829")); QVERIFY(!pp.up.fromStr("92ms")); QCOMPARE(pp.up.value(), 7829u); QVERIFY(pp.upc.toStr(str)); QCOMPARE(str, QString("9")); QVERIFY(pp.upc.fromStr(QString("11"))); QCOMPARE(pp.upc.value(), 11u); QVERIFY(pp.upc.toStr(str)); QCOMPARE(str, QString("11")); QVERIFY(!pp.upc.fromStr("-233")); QCOMPARE(pp.upc.value(), 11u); pp.upc.setMaxValue(100); QCOMPARE(pp.upc.value(), 11u); QVERIFY(!pp.upc.fromStr("110")); QCOMPARE(pp.upc.value(), 11u); QVERIFY(pp.fp.toStr(str)); QCOMPARE(str, QString("0")); QVERIFY(pp.fp.fromStr(QString("-23.2"))); QCOMPARE(pp.fp.value(), -23.2f); QVERIFY(pp.fp.toStr(str)); QCOMPARE(str, QString("-23.2")); QVERIFY(!pp.fp.fromStr("32.ws")); QCOMPARE(pp.fp.value(), -23.2f); QVERIFY(pp.fpc.toStr(str)); QCOMPARE(str, QString("0.2")); QVERIFY(pp.fpc.fromStr(QString("0.002"))); QCOMPARE(pp.fpc.value(), 0.002f); QVERIFY(pp.fpc.toStr(str)); QCOMPARE(str, QString("0.002")); QVERIFY(!pp.fpc.fromStr("-s233")); QCOMPARE(pp.fpc.value(), 0.002f); QVERIFY(pp.dp.toStr(str)); QCOMPARE(str, QString("0")); QVERIFY(pp.dp.fromStr(QString("9403.234"))); QCOMPARE(pp.dp.value(), 9403.234); QVERIFY(pp.dp.toStr(str)); QCOMPARE(str, QString("9403.234")); QVERIFY(!pp.dp.fromStr("94d03.234s")); QCOMPARE(pp.dp.value(), 9403.234); QVERIFY(pp.dpc.toStr(str)); QCOMPARE(str, QString("32.4")); QVERIFY(pp.dpc.fromStr(QString("-92.34"))); QCOMPARE(pp.dpc.value(), -92.34); QVERIFY(pp.dpc.toStr(str)); QCOMPARE(str, QString("-92.34")); QVERIFY(!pp.dpc.fromStr("weee")); QCOMPARE(pp.dpc.value(), -92.34); QVERIFY(pp.sp.toStr(str)); QCOMPARE(str, QString("")); QVERIFY(pp.sp.fromStr("Hello")); QCOMPARE(pp.sp.value(), QString("Hello")); QVERIFY(pp.sp.toStr(str)); QCOMPARE(str, QString("Hello")); QVERIFY(pp.sp.fromStr(" \"Hello world \" ")); QCOMPARE(pp.sp.value(), QString("\"Hello world \"")); QVERIFY(pp.spc.toStr(str)); QCOMPARE(str, QString("name")); QVERIFY(pp.spc.fromStr(QString("Name"))); QCOMPARE(pp.spc.value(), QString("Name")); QVERIFY(pp.spc.toStr(str)); QCOMPARE(str, QString("Name")); QVERIFY(pp.rp.toStr(str)); QCOMPARE(str, QString("QRect(0, 0, 0, 0)")); QVERIFY(pp.rp.fromStr(QString("QRect (-2, 3, 43, 45 ) "))); QCOMPARE(pp.rp.value(), QRect(-2, 3, 43, 45)); QVERIFY(pp.rp.toStr(str)); QCOMPARE(str, QString("QRect(-2, 3, 43, 45)")); QVERIFY(!pp.rp.fromStr("ddlwk,s")); QCOMPARE(pp.rp.value(), QRect(-2, 3, 43, 45)); QVERIFY(pp.rpc.toStr(str)); QCOMPARE(str, QString("QRect(10, 10, 10, 10)")); QVERIFY(pp.rpc.fromStr(QString("QRect(0, 0, 10, 10)"))); QCOMPARE(pp.rpc.value(), QRect(0, 0, 10, 10)); QVERIFY(pp.rpc.toStr(str)); QCOMPARE(str, QString("QRect(0, 0, 10, 10)")); QVERIFY(!pp.rpc.fromStr("weee")); QCOMPARE(pp.rpc.value(), QRect(0, 0, 10, 10)); QVERIFY(pp.rpf.toStr(str)); QCOMPARE(str, QString("QRectF(0, 0, 0, 0)")); QVERIFY(pp.rpf.fromStr(QString("QRectF (-2.3, 3.2, 43.5, 45.6 ) "))); QCOMPARE(pp.rpf.value(), QRectF(-2.3, 3.2, 43.5, 45.6)); QVERIFY(pp.rpf.toStr(str)); QCOMPARE(str, QString("QRectF(-2.3, 3.2, 43.5, 45.6)")); QVERIFY(!pp.rpf.fromStr("ddlwk,s")); QCOMPARE(pp.rpf.value(), QRectF(-2.3, 3.2, 43.5, 45.6)); QVERIFY(pp.rpfc.toStr(str)); QCOMPARE(str, QString("QRectF(10.1, 10.2, 10.3, 10.4)")); QVERIFY(pp.rpfc.fromStr(QString("QRectF(0.3, 0.0, 10.1, 10.1)"))); QCOMPARE(pp.rpfc.value(), QRectF(0.3, 0.0, 10.1, 10.10)); QVERIFY(pp.rpfc.toStr(str)); QCOMPARE(str, QString("QRectF(0.3, 0, 10.1, 10.1)")); QVERIFY(!pp.rpfc.fromStr("weee")); QCOMPARE(pp.rpfc.value(), QRectF(0.3, 0.0, 10.1, 10.1)); QVERIFY(pp.pp.toStr(str)); QCOMPARE(str, QString("QPoint(0, 0)")); QVERIFY(pp.pp.fromStr(QString("QPoint (-2, 3 ) "))); QCOMPARE(pp.pp.value(), QPoint(-2, 3)); QVERIFY(pp.pp.toStr(str)); QCOMPARE(str, QString("QPoint(-2, 3)")); QVERIFY(!pp.pp.fromStr("ddlwk,s")); QCOMPARE(pp.pp.value(), QPoint(-2, 3)); QVERIFY(pp.ppc.toStr(str)); QCOMPARE(str, QString("QPoint(9, 2)")); QVERIFY(pp.ppc.fromStr(QString("QPoint(-3, 20)"))); QCOMPARE(pp.ppc.value(), QPoint(-3, 20)); QVERIFY(pp.ppc.toStr(str)); QCOMPARE(str, QString("QPoint(-3, 20)")); QVERIFY(!pp.ppc.fromStr("weee")); QCOMPARE(pp.ppc.value(), QPoint(-3, 20)); QVERIFY(pp.ppf.toStr(str)); QCOMPARE(str, QString("QPointF(0, 0)")); QVERIFY(pp.ppf.fromStr(QString("QPointF (-2.2, 3.3 ) "))); QCOMPARE(pp.ppf.value(), QPointF(-2.2, 3.3)); QVERIFY(pp.ppf.toStr(str)); QCOMPARE(str, QString("QPointF(-2.2, 3.3)")); QVERIFY(!pp.ppf.fromStr("ddlwk,s")); QCOMPARE(pp.ppf.value(), QPointF(-2.2, 3.3)); QVERIFY(pp.ppfc.toStr(str)); QCOMPARE(str, QString("QPointF(9.9, 2.2)")); QVERIFY(pp.ppfc.fromStr(QString("QPointF(-3.3, 20.20)"))); QCOMPARE(pp.ppfc.value(), QPointF(-3.3, 20.20)); QVERIFY(pp.ppfc.toStr(str)); QCOMPARE(str, QString("QPointF(-3.3, 20.2)")); QVERIFY(!pp.ppfc.fromStr("weee")); QCOMPARE(pp.ppfc.value(), QPointF(-3.3, 20.20)); QVERIFY(pp.szp.toStr(str)); QCOMPARE(str, QString("QSize(-1, -1)")); QVERIFY(pp.szp.fromStr(QString("QSize (-2, 3 ) "))); QCOMPARE(pp.szp.value(), QSize(-2, 3)); QVERIFY(pp.szp.toStr(str)); QCOMPARE(str, QString("QSize(-2, 3)")); QVERIFY(!pp.szp.fromStr("ddlwk,s")); QCOMPARE(pp.szp.value(), QSize(-2, 3)); QVERIFY(pp.szpc.toStr(str)); QCOMPARE(str, QString("QSize(33, 21)")); QVERIFY(pp.szpc.fromStr(QString("QSize(-3, 20)"))); QCOMPARE(pp.szpc.value(), QSize(-3, 20)); QVERIFY(pp.szpc.toStr(str)); QCOMPARE(str, QString("QSize(-3, 20)")); QVERIFY(!pp.szpc.fromStr("weee")); QCOMPARE(pp.szpc.value(), QSize(-3, 20)); QVERIFY(pp.szpf.toStr(str)); QCOMPARE(str, QString("QSizeF(-1, -1)")); QVERIFY(pp.szpf.fromStr(QString("QSizeF (-2.3, 3.4 ) "))); QCOMPARE(pp.szpf.value(), QSizeF(-2.3, 3.4)); QVERIFY(pp.szpf.toStr(str)); QCOMPARE(str, QString("QSizeF(-2.3, 3.4)")); QVERIFY(!pp.szpf.fromStr("ddlwk,s")); QCOMPARE(pp.szpf.value(), QSizeF(-2.3, 3.4)); QVERIFY(pp.szpfc.toStr(str)); QCOMPARE(str, QString("QSizeF(33, 21.9)")); QVERIFY(pp.szpfc.fromStr(QString("QSizeF(-3.1, 20.8)"))); QCOMPARE(pp.szpfc.value(), QSizeF(-3.1, 20.8)); QVERIFY(pp.szpfc.toStr(str)); QCOMPARE(str, QString("QSizeF(-3.1, 20.8)")); QVERIFY(!pp.szpfc.fromStr("weee")); QCOMPARE(pp.szpfc.value(), QSizeF(-3.1, 20.8)); QVERIFY(pp.ep.toStr(str)); QCOMPARE(str, QString("BLUE")); QVERIFY(pp.ep.fromStr(QString(" Yellow \t"))); QCOMPARE(pp.ep.value(), (QtnEnumValueType) COLOR::YELLOW); QVERIFY(pp.ep.toStr(str)); QCOMPARE(str, QString("YELLOW")); QVERIFY(!pp.ep.fromStr("ddlwk,s")); QCOMPARE(pp.ep.value(), (QtnEnumValueType) COLOR::YELLOW); QVERIFY(pp.epc.toStr(str)); QCOMPARE(str, QString("RED")); QVERIFY(pp.epc.fromStr(QString("BlUe"))); QCOMPARE(pp.epc.value(), (QtnEnumValueType) COLOR::BLUE); QVERIFY(pp.epc.toStr(str)); QCOMPARE(str, QString("BLUE")); QVERIFY(!pp.epc.fromStr("COLOUR::Red")); QCOMPARE(pp.epc.value(), (QtnEnumValueType) COLOR::BLUE); QVERIFY(pp.efp.toStr(str)); QCOMPARE(str, QString("ONE|FOUR")); QVERIFY(pp.efp.fromStr(QString(" 0 \t"))); QCOMPARE(pp.efp.value(), 0); QVERIFY(pp.efp.toStr(str)); QCOMPARE(str, QString("0")); QVERIFY(pp.efp.fromStr("Two")); QCOMPARE(pp.efp.value(), (QtnEnumFlagsValueType) MASK::TWO); QVERIFY(pp.efp.fromStr("Two | Four")); QCOMPARE( pp.efp.value(), (QtnEnumFlagsValueType)(MASK::TWO | MASK::FOUR)); QVERIFY(!pp.efp.fromStr("Two&Four")); QCOMPARE( pp.efp.value(), (QtnEnumFlagsValueType)(MASK::TWO | MASK::FOUR)); QVERIFY(pp.efpc.toStr(str)); QCOMPARE(str, QString("ONE|FOUR")); QVERIFY(pp.efpc.fromStr(QString("Two"))); QCOMPARE(pp.efpc.value(), (QtnEnumFlagsValueType) MASK::TWO); QVERIFY(pp.efpc.toStr(str)); QCOMPARE(str, QString("TWO")); QVERIFY(!pp.efpc.fromStr("weee")); QCOMPARE(pp.efpc.value(), (QtnEnumFlagsValueType) MASK::TWO); QVERIFY(pp.cp.toStr(str)); QCOMPARE(str, QString("#0000ff")); QVERIFY(pp.cp.fromStr(QString(" Red \t"))); QCOMPARE(pp.cp.value(), QColor(Qt::red)); QVERIFY(pp.cp.toStr(str)); QCOMPARE(str, QString("#ff0000")); QVERIFY(!pp.cp.fromStr("ddlwk,s")); QCOMPARE(pp.cp.value(), QColor(Qt::red)); QVERIFY(pp.cpc.toStr(str)); QCOMPARE(str, QString("#ff0000")); QVERIFY(pp.cpc.fromStr(QString("transparent"))); QCOMPARE(pp.cpc.value(), QColor(Qt::transparent)); QVERIFY(pp.cpc.toStr(str)); QCOMPARE(str, QString("#00000000")); QVERIFY(!pp.cpc.fromStr("COLOUR::Red")); QCOMPARE(pp.cpc.value(), QColor(Qt::transparent)); QVERIFY(pp.fnp.toStr(str)); QCOMPARE(str, QString("Courier,10,-1,5,50,0,0,0,0,0")); QVERIFY(pp.fnp.fromStr(QString(" Arial,18,-1,5,50,0,0,0,0,0 \t"))); QCOMPARE(pp.fnp.value(), QFont("Arial", 18)); QVERIFY(pp.fnp.toStr(str)); QCOMPARE(str, QString("Arial,18,-1,5,50,0,0,0,0,0")); QVERIFY(pp.fnpc.toStr(str)); QCOMPARE(str, QString("Arial,19,-1,5,50,0,0,0,0,0")); QVERIFY(pp.fnpc.fromStr(QString("Mono,23"))); QFont font; font.setFamily("Mono"); font.setPointSize(23); QCOMPARE(pp.fnpc.value(), font); QVERIFY(pp.fnpc.toStr(str)); QCOMPARE(str, QString("Mono,23,-1,5,50,0,0,0,0,0")); } { QtnPropertySetTest3 p(this); QCOMPARE(p.iis.a.value(), true); QVERIFY(p.fromStr("iis.a = false")); QCOMPARE(p.iis.a.value(), false); QCOMPARE(p.u.value(), true); QCOMPARE(p.yy.s.value(), QString("")); QCOMPARE(p.s.a.value(), false); QVERIFY(p.fromStr("u = False\r\nyy.s = \"new value\"\n s.a=true")); QCOMPARE(p.u.value(), false); QCOMPARE(p.yy.s.value(), QString("new value")); QCOMPARE(p.s.a.value(), true); } { QtnPropertySet ps(this); QtnPropertyBool pb(&ps); pb.setName("AAAA"); pb.setDisplayName("AA AA"); pb.setValue(false); QtnPropertyInt pi(&ps); pi.setName("BBBB"); pi.setDisplayName("BB BB"); pi.setValue(12); { QString res; QVERIFY(ps.toStr(res)); QVERIFY(ps.fromStr(res)); } pb.addState(QtnPropertyStateInvisible); { QString res; QVERIFY(ps.toStr(res)); QVERIFY(ps.fromStr(res)); } } { QtnPropertySetTest12 ps(this); QString res; QVERIFY(ps.toStr(res)); QVERIFY(ps.fromStr(res)); } } void TestProperty::qObjectProperty() { { QObject obj; obj.setObjectName("Item1"); QtnProperty *p = qtnCreateQObjectProperty(&obj, "objectName"); QVERIFY(p); QtnPropertyQStringBase *ps = qobject_cast(p); QVERIFY(ps); QCOMPARE(ps->value(), QString("Item1")); QCOMPARE(ps->state(), QtnPropertyStateNone); ps->setValue("NewItemName"); QCOMPARE(obj.objectName(), QString("NewItemName")); QCOMPARE(ps->value(), QString("NewItemName")); } } void TestProperty::qObjectPropertySet() { { QObject obj; obj.setObjectName("name"); QtnPropertySet *p = qtnCreateQObjectPropertySet(&obj); QVERIFY(p); QCOMPARE(p->name(), QString("name")); const QList &subPropertySets = p->childProperties(); QCOMPARE(subPropertySets.size(), 1); QtnPropertySet *p1 = subPropertySets[0]->asPropertySet(); QVERIFY(p1); QCOMPARE(p1->name(), QString("QObject")); QCOMPARE(p1->childProperties().size(), 1); } { QCoreApplication *app = QCoreApplication::instance(); QVERIFY(app); QtnPropertySet *p = qtnCreateQObjectPropertySet(app); QVERIFY(p); } } void TestProperty::checkPropertyStateIsNonSimple( QtnPropertyChangeReason reason, QtnPropertyValuePtr newValue, int typeId) { QCOMPARE(typeId, qMetaTypeId()); QCOMPARE(reason, QtnPropertyChangeReasonStateLocal); auto state = qtnCastPropertyValue(newValue); QVERIFY(state); QCOMPARE(*state, QtnPropertyStateNonSimple | QtnPropertyStateResettable); } ================================================ FILE: Tests/TestProperty.h ================================================ #ifndef TEST_PROPERTY_H #define TEST_PROPERTY_H #include "QtnProperty/Property.h" #include class TestProperty : public QObject { Q_OBJECT public: Q_INVOKABLE TestProperty() {} private Q_SLOTS: void name(); void description(); void id(); void state(); void stateChange(); void propertyDelegate(); void propertyDelegateCallback(); void propertyBool(); void propertyInt(); void propertyString(); void propertyRect(); void propertyEnum(); void propertyEnumFlags(); void propertyPen(); void propertyVector3D(); void propertySet(); void serializationState(); void serializationChildren(); void serializationValue(); void createNew(); void createCopy(); void copyValues(); void propertyAssignment(); void propertyScripting(); void variantConversions(); void stringConversions(); void qObjectProperty(); void qObjectPropertySet(); public Q_SLOTS: void checkPropertyStateIsNonSimple(QtnPropertyChangeReason reason, QtnPropertyValuePtr newValue, int typeId); }; #endif // TEST_PROPERTY_H ================================================ FILE: Tests/Tests.pro ================================================ include(../QtnPropertyDepend.pri) include(../Internal/TargetConfig.pri) include(../PEG/PEG.pri) QT += core gui widgets script testlib TARGET = QtnPropertyTests CONFIG += cmdline CONFIG -= app_bundle TEMPLATE = app HEADERS += \ TestProperty.h \ TestGeneratedProperty.h \ TestEnum.h SOURCES += main.cpp \ TestProperty.cpp \ TestGeneratedProperty.cpp \ TestEnum.cpp PEG_SOURCES += PEG/test.pef \ PEG/test2.pef OTHER_FILES += $$PEG_SOURCES ================================================ FILE: Tests/main.cpp ================================================ #include "TestProperty.h" #include "TestGeneratedProperty.h" #include "TestEnum.h" #include #include int main(int argc, char *argv[]) { qInfo("Init tests..."); QCoreApplication app(argc, argv); int result = 0; QList tests; // register tests tests.append(&TestProperty::staticMetaObject); tests.append(&TestGeneratedProperty::staticMetaObject); tests.append(&TestEnum::staticMetaObject); // run tests foreach (const QMetaObject *testMetaObject, tests) { QScopedPointer test(testMetaObject->newInstance()); Q_ASSERT(test); if (test) { result |= QTest::qExec(test.data(), argc, argv); } } return result; } ================================================ FILE: Tests/suite_squish_test_suit/envvars ================================================ ================================================ FILE: Tests/suite_squish_test_suit/suite.conf ================================================ AUT=QtnPropertyDemo CWD= ENVVARS=envvars HOOK_SUB_PROCESSES=false IMPLICITAUTSTART=1 LANGUAGE=JavaScript TEST_CASES=tst_gui_test VERSION=3 WRAPPERS=Qt ================================================ FILE: Tests/suite_squish_test_suit/tst_gui_test/test.js ================================================ function waitForChild() { if (arguments.length < 2) return null var obj = arguments[0] objectMap.add(obj) obj = waitForObject("{type='"+arguments[1]+"' parent='"+objectMap.symbolicName(obj)+"'}") for (var i = 2; i < arguments.length; i++) { objectMap.add(obj) obj = waitForObject("{type='"+arguments[i]+"' parent='"+objectMap.symbolicName(obj)+"'}") } return obj } function main() { var w = waitForObject("{type='QtnPropertyView' visible='1' window=':PropertyWidget Demo_MainWindow'}") var ap = w.accessibilityProxy() // test BoolProperty var p = ap.findProperty("BoolProperty") test.verify(!isNull(p), "BoolProperty should exists") // check property value test.compare(object.convertTo(p.value,"bool"), false) // check property delegate name test.compare(ap.propertyDelegateName(p), "default") // check property description test.compare(p.description, "Property to hold boolean values.") // get center of property edit rect var pt = ap.propertyActionRect(p, 0).center() mouseClick(w, pt.x, pt.y, Qt.NoModifier, Qt.LeftButton) snooze(1) // wait for popup checkbox widget var e = waitForChild(w, "QCheckBox") test.compare(e.checked, false) // modify property pt = e.rect.center() mouseClick(e, pt.x, pt.y, Qt.NoModifier, Qt.LeftButton) type(e, "") test.compare(object.convertTo(p.value,"bool"), true) snooze(1) // enable subproperty set p = ap.findProperty("EnableSubPropertySet") test.verify(!isNull(p)) // get center of property name rect pt = ap.propertyNameRect(p).center() // activate property mouseClick(w, pt.x, pt.y, Qt.NoModifier, Qt.LeftButton) snooze(1) var p2 = ap.activeProperty() test.compare(p, p2, "EnableSubPropertySet should become active") // verify SubPropertySet is disabled p2 = ap.findProperty("SubPropertySet") test.verify(!isNull(p2)) test.compare(p2.isEditable, false) test.compare(p2.state, 4) // QtnPropertyStateImmutable // start edit type(w, "") snooze(1) // wait for popup checkbox widget e = waitForChild(w, "QCheckBox") type(e, " ") type(e, "") // now SubPropertySet should be enabled test.compare(p2.isEditable, true) test.compare(p2.state, 0) // navigation by keyboard snooze(1) type(w, "") test.compare(ap.activeProperty().name, "SubPropertySet") snooze(1) // collapse property set by keyboard type(w, "") p = ap.findProperty("SubPropertySet.ReadOnlyString") test.verify(!isNull(p)) test.compare(p.isEditable, false) test.compare(p.state, 12) // QtnPropertyStateImmutable | QtnPropertyStateCollapsed snooze(1) // expand property set by mouse pt = ap.propertyActionRect(ap.findProperty("SubPropertySet"), 0).center() mouseClick(w, pt.x, pt.y, Qt.NoModifier, Qt.LeftButton) test.compare(p.state, 4) // QtnPropertyStateImmutable snooze(1) //test string list delegate p = ap.findProperty("SubPropertySet.StringFromList") pt = ap.propertyActionRect(p, 0).center() mouseClick(w, pt.x, pt.y, Qt.NoModifier, Qt.LeftButton) e = waitForChild(w, "QComboBox") // get popup listbox e = e.view() snooze(1) clickItem(e, "four", 0, 0, Qt.NoModifier, Qt.LeftButton) // check property value test.compare(object.convertTo(p.value,"QString"), "four") snooze(1) p = ap.findProperty("SubPropertySet2.FileNameProperty") ap.ensureVisibleProperty(p) p = ap.propertyActionRect(p, 0).center() mouseClick(w, p.x, p.y, Qt.NoModifier, Qt.LeftButton) snooze(1) e = waitForChild(w, "QLineEdit") type(e, "hello from squish") type(e, "") snooze(3) return }