forked from qt-creator/qt-creator
QmlDesigner: Add percentages to GradientModel
Task-number: QDS-9904 Change-Id: I98c9e67e46f282053755d143af19eb83f62a5c72 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
@@ -959,6 +959,7 @@ T.Popup {
|
||||
|
||||
component ControlsRow: RowLayout {
|
||||
property alias propertyName: spinBox.propertyName
|
||||
property alias gradientTypeName: spinBox.gradientTypeName
|
||||
property alias labelText: label.text
|
||||
property alias labelTooltip: label.tooltip
|
||||
property alias value: spinBox.value
|
||||
@@ -980,21 +981,21 @@ T.Popup {
|
||||
}
|
||||
}
|
||||
|
||||
ControlLabel {
|
||||
id: label
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
width: StudioTheme.Values.controlGap
|
||||
+ StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||
}
|
||||
|
||||
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||
|
||||
GradientPropertySpinBox {
|
||||
id: spinBox
|
||||
implicitWidth: StudioTheme.Values.controlGap
|
||||
+ 2 * StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||
width: implicitWidth
|
||||
}
|
||||
|
||||
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||
|
||||
ControlLabel {
|
||||
id: label
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
width: StudioTheme.Values.controlGap
|
||||
+ 2 * StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||
}
|
||||
}
|
||||
|
||||
// Default Gradient Controls
|
||||
@@ -1051,31 +1052,32 @@ T.Popup {
|
||||
id: linearGradientControls
|
||||
spacing: 10
|
||||
visible: cePopup.hasLinearGradient() && colorEditor.shapeGradients
|
||||
readonly property string gradientTypeName: "LinearGradient"
|
||||
|
||||
ControlsRow {
|
||||
id: linearGradientX1
|
||||
propertyName: "x1"
|
||||
gradientTypeName: linearGradientControls.gradientTypeName
|
||||
labelText: "X1"
|
||||
labelTooltip: qsTr("Defines the start point for color interpolation.")
|
||||
}
|
||||
|
||||
ControlsRow {
|
||||
id: linearGradientX2
|
||||
propertyName: "x2"
|
||||
gradientTypeName: linearGradientControls.gradientTypeName
|
||||
labelText: "X2"
|
||||
labelTooltip: qsTr("Defines the end point for color interpolation.")
|
||||
}
|
||||
|
||||
ControlsRow {
|
||||
id: linearGradientY1
|
||||
propertyName: "y1"
|
||||
gradientTypeName: linearGradientControls.gradientTypeName
|
||||
labelText: "Y1"
|
||||
labelTooltip: qsTr("Defines the start point for color interpolation.")
|
||||
}
|
||||
|
||||
ControlsRow {
|
||||
id: linearGradientY2
|
||||
propertyName: "y2"
|
||||
gradientTypeName: linearGradientControls.gradientTypeName
|
||||
labelText: "Y2"
|
||||
labelTooltip: qsTr("Defines the end point for color interpolation.")
|
||||
}
|
||||
@@ -1086,39 +1088,46 @@ T.Popup {
|
||||
id: radialGradientControls
|
||||
spacing: 10
|
||||
visible: cePopup.hasRadialGradient()
|
||||
readonly property string gradientTypeName: "RadialGradient"
|
||||
|
||||
ControlsRow {
|
||||
propertyName: "centerX"
|
||||
gradientTypeName: radialGradientControls.gradientTypeName
|
||||
labelText: "CenterX"
|
||||
labelTooltip: qsTr("Defines the center point.")
|
||||
}
|
||||
|
||||
ControlsRow {
|
||||
propertyName: "centerY"
|
||||
gradientTypeName: radialGradientControls.gradientTypeName
|
||||
labelText: "CenterY"
|
||||
labelTooltip: qsTr("Defines the center point.")
|
||||
}
|
||||
|
||||
ControlsRow {
|
||||
propertyName: "focalX"
|
||||
gradientTypeName: radialGradientControls.gradientTypeName
|
||||
labelText: "FocalX"
|
||||
labelTooltip: qsTr("Defines the focal point.")
|
||||
}
|
||||
|
||||
ControlsRow {
|
||||
propertyName: "focalY"
|
||||
gradientTypeName: radialGradientControls.gradientTypeName
|
||||
labelText: "FocalY"
|
||||
labelTooltip: qsTr("Defines the focal point.")
|
||||
}
|
||||
|
||||
ControlsRow {
|
||||
propertyName: "centerRadius"
|
||||
gradientTypeName: radialGradientControls.gradientTypeName
|
||||
labelText: "Center Radius"
|
||||
labelTooltip: qsTr("Defines the center radius.")
|
||||
}
|
||||
|
||||
ControlsRow {
|
||||
propertyName: "focalRadius"
|
||||
gradientTypeName: radialGradientControls.gradientTypeName
|
||||
labelText: "Focal Radius"
|
||||
labelTooltip: qsTr("Defines the focal radius. Set to 0 for simple radial gradients.")
|
||||
}
|
||||
@@ -1126,24 +1135,28 @@ T.Popup {
|
||||
|
||||
// Conical Gradient Controls
|
||||
Column {
|
||||
id: concialGradientControls
|
||||
id: conicalGradientControls
|
||||
spacing: 10
|
||||
visible: cePopup.hasConicalGradient()
|
||||
readonly property string gradientTypeName: "ConicalGradient"
|
||||
|
||||
ControlsRow {
|
||||
propertyName: "centerX"
|
||||
gradientTypeName: conicalGradientControls.gradientTypeName
|
||||
labelText: "CenterX"
|
||||
labelTooltip: qsTr("Defines the center point.")
|
||||
}
|
||||
|
||||
ControlsRow {
|
||||
propertyName: "centerY"
|
||||
gradientTypeName: conicalGradientControls.gradientTypeName
|
||||
labelText: "CenterY"
|
||||
labelTooltip: qsTr("Defines the center point.")
|
||||
}
|
||||
|
||||
ControlsRow {
|
||||
propertyName: "angle"
|
||||
gradientTypeName: conicalGradientControls.gradientTypeName
|
||||
labelText: "Angle"
|
||||
labelTooltip: qsTr("Defines the start angle for the conical gradient. The value is in degrees (0-360).")
|
||||
}
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import StudioControls 1.0 as StudioControls
|
||||
import StudioTheme 1.0 as StudioTheme
|
||||
|
||||
Item {
|
||||
SecondColumnLayout {
|
||||
id: wrapper
|
||||
|
||||
property string propertyName
|
||||
property string gradientTypeName
|
||||
|
||||
property alias decimals: spinBox.decimals
|
||||
property alias value: spinBox.realValue
|
||||
@@ -23,8 +25,20 @@ Item {
|
||||
|
||||
onFocusChanged: restoreCursor()
|
||||
|
||||
property bool __isPercentage: false
|
||||
property bool __mightHavePercents: gradientLine.model.isPercentageSupportedByProperty(wrapper.propertyName, wrapper.gradientTypeName)
|
||||
|
||||
function readValue() {
|
||||
spinBox.realValue = gradientLine.model.readGradientProperty(wrapper.propertyName)
|
||||
wrapper.__isPercentage = (gradientLine.model.readGradientPropertyUnits(wrapper.propertyName) === GradientModel.Percentage);
|
||||
|
||||
if (wrapper.__isPercentage) {
|
||||
unitType.currentIndex = 1;
|
||||
spinBox.realValue = gradientLine.model.readGradientPropertyPercentage(wrapper.propertyName)
|
||||
}
|
||||
else {
|
||||
unitType.currentIndex = 0;
|
||||
spinBox.realValue = gradientLine.model.readGradientProperty(wrapper.propertyName)
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.RealSpinBox {
|
||||
@@ -32,21 +46,52 @@ Item {
|
||||
|
||||
__devicePixelRatio: devicePixelRatio()
|
||||
|
||||
width: wrapper.width
|
||||
implicitWidth: StudioTheme.Values.colorEditorPopupSpinBoxWidth * 1.5
|
||||
width: implicitWidth
|
||||
actionIndicatorVisible: false
|
||||
|
||||
realFrom: -9999
|
||||
realTo: 9999
|
||||
realStepSize: 1
|
||||
decimals: 0
|
||||
realStepSize: wrapper.__isPercentage ? 0.1 : 1
|
||||
decimals: wrapper.__isPercentage ? 4 : 0
|
||||
|
||||
Component.onCompleted: wrapper.readValue()
|
||||
onCompressedRealValueModified: {
|
||||
gradientLine.model.setGradientProperty(wrapper.propertyName, spinBox.realValue)
|
||||
if (wrapper.__isPercentage)
|
||||
gradientLine.model.setGradientPropertyPercentage(wrapper.propertyName, spinBox.realValue)
|
||||
else
|
||||
gradientLine.model.setGradientProperty(wrapper.propertyName, spinBox.realValue)
|
||||
}
|
||||
|
||||
onDragStarted: hideCursor()
|
||||
onDragEnded: restoreCursor()
|
||||
onDragging: holdCursorInPlace()
|
||||
}
|
||||
|
||||
Spacer {
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||
}
|
||||
|
||||
StudioControls.ComboBox {
|
||||
id: unitType
|
||||
implicitWidth: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||
width: implicitWidth
|
||||
model: ["px", "%"] //px = 0, % = 1
|
||||
actionIndicatorVisible: false
|
||||
visible: wrapper.__mightHavePercents
|
||||
|
||||
onActivated: {
|
||||
if (!wrapper.__mightHavePercents)
|
||||
return
|
||||
|
||||
if (unitType.currentIndex === 0)
|
||||
gradientLine.model.setGradientPropertyUnits(wrapper.propertyName, GradientModel.Pixels)
|
||||
else
|
||||
gradientLine.model.setGradientPropertyUnits(wrapper.propertyName, GradientModel.Percentage)
|
||||
|
||||
wrapper.readValue()
|
||||
}
|
||||
}
|
||||
|
||||
ExpandingSpacer {}
|
||||
}
|
||||
|
||||
@@ -3,24 +3,182 @@
|
||||
|
||||
#include "gradientmodel.h"
|
||||
|
||||
#include "qmlanchorbindingproxy.h"
|
||||
#include "propertyeditorview.h"
|
||||
#include "gradientpresetitem.h"
|
||||
#include "gradientpresetcustomlistmodel.h"
|
||||
#include "gradientpresetitem.h"
|
||||
#include "propertyeditorview.h"
|
||||
#include "qmlanchorbindingproxy.h"
|
||||
|
||||
#include <exception.h>
|
||||
#include <nodeproperty.h>
|
||||
#include <nodelistproperty.h>
|
||||
#include <variantproperty.h>
|
||||
#include <abstractview.h>
|
||||
#include <nodemetainfo.h>
|
||||
#include <exception.h>
|
||||
#include <nodelistproperty.h>
|
||||
#include <nodemetainfo.h>
|
||||
#include <nodeproperty.h>
|
||||
#include <rewritertransaction.h>
|
||||
#include <variantproperty.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QTimer>
|
||||
#include <QScopeGuard>
|
||||
#include <QTimer>
|
||||
|
||||
namespace {
|
||||
constexpr auto defaultValueLinearX1 = [](const QmlDesigner::QmlItemNode &) -> qreal { return 0.0; };
|
||||
constexpr auto defaultValueLinearY1 = [](const QmlDesigner::QmlItemNode &) -> qreal { return 0.0; };
|
||||
constexpr auto defaultValueLinearX2 = [](const QmlDesigner::QmlItemNode &node) -> qreal {
|
||||
return node.instanceValue("width").toReal();
|
||||
};
|
||||
constexpr auto defaultValueLinearY2 = [](const QmlDesigner::QmlItemNode &node) -> qreal {
|
||||
return node.instanceValue("height").toReal();
|
||||
};
|
||||
constexpr auto defaultValueRadialCenterRadius = [](const QmlDesigner::QmlItemNode &node) -> qreal {
|
||||
const qreal width = node.instanceValue("width").toReal();
|
||||
const qreal height = node.instanceValue("height").toReal();
|
||||
return qMin(width, height) / 2.0;
|
||||
};
|
||||
constexpr auto defaultValueRadialCenterX = [](const QmlDesigner::QmlItemNode &node) -> qreal {
|
||||
return (node.instanceValue("width").toReal() / 2.0);
|
||||
};
|
||||
constexpr auto defaultValueRadialCenterY = [](const QmlDesigner::QmlItemNode &node) -> qreal {
|
||||
return (node.instanceValue("height").toReal() / 2.0);
|
||||
};
|
||||
constexpr auto defaultValueRadialFocalRadius = [](const QmlDesigner::QmlItemNode &) -> qreal {
|
||||
return 0.0;
|
||||
};
|
||||
constexpr auto defaultValueRadialFocalX = [](const QmlDesigner::QmlItemNode &node) -> qreal {
|
||||
return (node.instanceValue("width").toReal() / 2.0);
|
||||
};
|
||||
constexpr auto defaultValueRadialFocalY = [](const QmlDesigner::QmlItemNode &node) -> qreal {
|
||||
return (node.instanceValue("height").toReal() / 2.0);
|
||||
};
|
||||
constexpr auto defaultValueConicalAngle = [](const QmlDesigner::QmlItemNode &) -> qreal {
|
||||
return 0.0;
|
||||
};
|
||||
constexpr auto defaultValueConicalCenterX = [](const QmlDesigner::QmlItemNode &node) -> qreal {
|
||||
return (node.instanceValue("width").toReal() / 2.0);
|
||||
};
|
||||
constexpr auto defaultValueConicalCenterY = [](const QmlDesigner::QmlItemNode &node) -> qreal {
|
||||
return (node.instanceValue("height").toReal() / 2.0);
|
||||
};
|
||||
|
||||
using DefaultValueFunctionVariant = std::variant<std::monostate,
|
||||
decltype(defaultValueLinearX1),
|
||||
decltype(defaultValueLinearY1),
|
||||
decltype(defaultValueLinearX2),
|
||||
decltype(defaultValueLinearY2),
|
||||
decltype(defaultValueRadialCenterRadius),
|
||||
decltype(defaultValueRadialCenterX),
|
||||
decltype(defaultValueRadialCenterY),
|
||||
decltype(defaultValueRadialFocalRadius),
|
||||
decltype(defaultValueRadialFocalX),
|
||||
decltype(defaultValueRadialFocalY),
|
||||
decltype(defaultValueConicalAngle),
|
||||
decltype(defaultValueConicalCenterX),
|
||||
decltype(defaultValueConicalCenterY)>;
|
||||
} // namespace
|
||||
|
||||
class ShapeGradientPropertyData
|
||||
{
|
||||
public:
|
||||
enum class UsePercents { No, Yes };
|
||||
|
||||
constexpr ShapeGradientPropertyData() = default;
|
||||
|
||||
constexpr ShapeGradientPropertyData(QmlDesigner::PropertyNameView name,
|
||||
QmlDesigner::PropertyNameView bindingProperty,
|
||||
UsePercents canPercent,
|
||||
DefaultValueFunctionVariant defVariant)
|
||||
: name(name)
|
||||
, bindingProperty(bindingProperty)
|
||||
, canUsePercentage(canPercent)
|
||||
, m_defaultValue(defVariant)
|
||||
{}
|
||||
|
||||
QmlDesigner::PropertyNameView name;
|
||||
QmlDesigner::PropertyNameView bindingProperty;
|
||||
UsePercents canUsePercentage = UsePercents::No;
|
||||
|
||||
private:
|
||||
DefaultValueFunctionVariant m_defaultValue;
|
||||
|
||||
public:
|
||||
constexpr qreal getDefaultValue(const QmlDesigner::QmlItemNode &itemNode) const
|
||||
{
|
||||
return std::visit(
|
||||
[&](auto &defValue) -> qreal {
|
||||
using Type = std::decay_t<decltype(defValue)>;
|
||||
if constexpr (std::is_same_v<Type, std::monostate>)
|
||||
return 0.0;
|
||||
else
|
||||
return defValue(itemNode);
|
||||
},
|
||||
m_defaultValue);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr QmlDesigner::PropertyNameView linearX1Str = u8"x1";
|
||||
constexpr QmlDesigner::PropertyNameView linearX2Str = u8"x2";
|
||||
constexpr QmlDesigner::PropertyNameView linearY1Str = u8"y1";
|
||||
constexpr QmlDesigner::PropertyNameView linearY2Str = u8"y2";
|
||||
|
||||
constexpr QmlDesigner::PropertyNameView radialCenterRadiusStr = u8"centerRadius";
|
||||
constexpr QmlDesigner::PropertyNameView radialCenterXStr = u8"centerX";
|
||||
constexpr QmlDesigner::PropertyNameView radialCenterYStr = u8"centerY";
|
||||
constexpr QmlDesigner::PropertyNameView radialFocalRadiusStr = u8"focalRadius";
|
||||
constexpr QmlDesigner::PropertyNameView radialFocalXStr = u8"focalX";
|
||||
constexpr QmlDesigner::PropertyNameView radialFocalYStr = u8"focalY";
|
||||
|
||||
constexpr QmlDesigner::PropertyNameView conicalAngleStr = u8"angle";
|
||||
constexpr QmlDesigner::PropertyNameView conicalCenterXStr = u8"centerX";
|
||||
constexpr QmlDesigner::PropertyNameView conicalCenterYStr = u8"centerY";
|
||||
|
||||
constexpr ShapeGradientPropertyData defaultLinearShapeGradients[] = {
|
||||
{linearX1Str, u8"width", ShapeGradientPropertyData::UsePercents::Yes, defaultValueLinearX1},
|
||||
{linearX2Str, u8"width", ShapeGradientPropertyData::UsePercents::Yes, defaultValueLinearX2},
|
||||
{linearY1Str, u8"height", ShapeGradientPropertyData::UsePercents::Yes, defaultValueLinearY1},
|
||||
{linearY2Str, u8"height", ShapeGradientPropertyData::UsePercents::Yes, defaultValueLinearY2}};
|
||||
|
||||
constexpr ShapeGradientPropertyData defaultRadialShapeGradients[] = {
|
||||
{radialCenterRadiusStr, u8"", ShapeGradientPropertyData::UsePercents::No, defaultValueRadialCenterRadius},
|
||||
{radialCenterXStr, u8"width", ShapeGradientPropertyData::UsePercents::Yes, defaultValueRadialCenterX},
|
||||
{radialCenterYStr, u8"height", ShapeGradientPropertyData::UsePercents::Yes, defaultValueRadialCenterY},
|
||||
{radialFocalRadiusStr, u8"", ShapeGradientPropertyData::UsePercents::No, defaultValueRadialFocalRadius},
|
||||
{radialFocalXStr, u8"width", ShapeGradientPropertyData::UsePercents::Yes, defaultValueRadialFocalX},
|
||||
{radialFocalYStr, u8"height", ShapeGradientPropertyData::UsePercents::Yes, defaultValueRadialFocalY}};
|
||||
|
||||
constexpr ShapeGradientPropertyData defaultConicalShapeGradients[] = {
|
||||
{conicalAngleStr, u8"", ShapeGradientPropertyData::UsePercents::No, defaultValueConicalAngle},
|
||||
{conicalCenterXStr, u8"width", ShapeGradientPropertyData::UsePercents::Yes, defaultValueConicalCenterX},
|
||||
{conicalCenterYStr,
|
||||
u8"height",
|
||||
ShapeGradientPropertyData::UsePercents::Yes,
|
||||
defaultValueConicalCenterY}};
|
||||
|
||||
template<typename GradientArrayType>
|
||||
const ShapeGradientPropertyData *findGradientInArray(const GradientArrayType &array,
|
||||
const QmlDesigner::PropertyNameView propName)
|
||||
{
|
||||
const auto found = std::find_if(std::begin(array), std::end(array), [&](const auto &entry) {
|
||||
return entry.name == propName;
|
||||
});
|
||||
if (found != std::end(array))
|
||||
return std::addressof(*found);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ShapeGradientPropertyData *getDefaultGradientData(const QmlDesigner::PropertyNameView propName,
|
||||
const QStringView &gradientType)
|
||||
{
|
||||
if (gradientType == u"LinearGradient") {
|
||||
return findGradientInArray(defaultLinearShapeGradients, propName);
|
||||
} else if (gradientType == u"RadialGradient") {
|
||||
return findGradientInArray(defaultRadialShapeGradients, propName);
|
||||
} else if (gradientType == u"ConicalGradient") {
|
||||
return findGradientInArray(defaultConicalShapeGradients, propName);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GradientModel::GradientModel(QObject *parent) :
|
||||
QAbstractListModel(parent)
|
||||
@@ -268,7 +426,7 @@ void GradientModel::unlock()
|
||||
|
||||
void GradientModel::registerDeclarativeType()
|
||||
{
|
||||
qmlRegisterType<GradientModel>("HelperWidgets",2,0,"GradientModel");
|
||||
qmlRegisterType<GradientModel>("HelperWidgets", 2, 0, "GradientModel");
|
||||
}
|
||||
|
||||
qreal GradientModel::readGradientProperty(const QString &propertyName) const
|
||||
@@ -276,10 +434,9 @@ qreal GradientModel::readGradientProperty(const QString &propertyName) const
|
||||
if (!m_itemNode.isValid())
|
||||
return 0;
|
||||
|
||||
QmlDesigner::QmlObjectNode gradient;
|
||||
|
||||
if (m_itemNode.modelNode().hasProperty(gradientPropertyName().toUtf8()))
|
||||
gradient = m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).modelNode();
|
||||
QmlDesigner::QmlObjectNode gradient = m_itemNode.modelNode()
|
||||
.nodeProperty(gradientPropertyName().toUtf8())
|
||||
.modelNode();
|
||||
|
||||
if (!gradient.isValid())
|
||||
return 0;
|
||||
@@ -287,15 +444,19 @@ qreal GradientModel::readGradientProperty(const QString &propertyName) const
|
||||
return gradient.modelValue(propertyName.toUtf8()).toReal();
|
||||
}
|
||||
|
||||
qreal GradientModel::readGradientPropertyPercentage(const QString &propertyName) const
|
||||
{
|
||||
return getPercentageGradientProperty(propertyName.toUtf8());
|
||||
}
|
||||
|
||||
QString GradientModel::readGradientOrientation() const
|
||||
{
|
||||
if (!m_itemNode.isValid())
|
||||
return QString();
|
||||
|
||||
QmlDesigner::QmlObjectNode gradient;
|
||||
|
||||
if (m_itemNode.modelNode().hasProperty(gradientPropertyName().toUtf8()))
|
||||
gradient = m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).modelNode();
|
||||
QmlDesigner::QmlObjectNode gradient = m_itemNode.modelNode()
|
||||
.nodeProperty(gradientPropertyName().toUtf8())
|
||||
.modelNode();
|
||||
|
||||
if (!gradient.isValid())
|
||||
return QString();
|
||||
@@ -303,6 +464,25 @@ QString GradientModel::readGradientOrientation() const
|
||||
return gradient.modelValue("orientation").value<QmlDesigner::Enumeration>().nameToString();
|
||||
}
|
||||
|
||||
GradientModel::GradientPropertyUnits GradientModel::readGradientPropertyUnits(
|
||||
const QString &propertyName) const
|
||||
{
|
||||
if (hasPercentageGradientProperty(propertyName))
|
||||
return GradientPropertyUnits::Percentage;
|
||||
|
||||
return GradientPropertyUnits::Pixels;
|
||||
}
|
||||
|
||||
bool GradientModel::isPercentageSupportedByProperty(const QString &propertyName,
|
||||
const QString &gradientTypeName) const
|
||||
{
|
||||
const auto gradientPropertyData = getDefaultGradientPropertyData(propertyName.toUtf8(), gradientTypeName);
|
||||
if (!gradientPropertyData.name.isEmpty())
|
||||
return gradientPropertyData.canUsePercentage == ShapeGradientPropertyData::UsePercents::Yes;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GradientModel::setupModel()
|
||||
{
|
||||
m_locked = true;
|
||||
@@ -400,34 +580,29 @@ void GradientModel::setupGradientProperties(const QmlDesigner::ModelNode &gradie
|
||||
|
||||
QTC_ASSERT(gradient.isValid(), return);
|
||||
|
||||
if (m_gradientTypeName == "Gradient") {
|
||||
if (m_gradientTypeName == u"Gradient") {
|
||||
gradient.variantProperty("orientation").setEnumeration("Gradient.Vertical");
|
||||
} else if (m_gradientTypeName == "LinearGradient") {
|
||||
gradient.variantProperty("x1").setValue(0);
|
||||
gradient.variantProperty("x2").setValue(m_itemNode.instanceValue("width"));
|
||||
gradient.variantProperty("y1").setValue(0);
|
||||
gradient.variantProperty("y2").setValue(m_itemNode.instanceValue("height"));
|
||||
} else if (m_gradientTypeName == "RadialGradient") {
|
||||
qreal width = m_itemNode.instanceValue("width").toReal();
|
||||
qreal height = m_itemNode.instanceValue("height").toReal();
|
||||
gradient.variantProperty("centerX").setValue(width / 2.0);
|
||||
gradient.variantProperty("centerY").setValue(height / 2.0);
|
||||
|
||||
gradient.variantProperty("focalX").setValue(width / 2.0);
|
||||
gradient.variantProperty("focalY").setValue(height / 2.0);
|
||||
|
||||
qreal radius = qMin(width, height) / 2;
|
||||
|
||||
gradient.variantProperty("centerRadius").setValue(radius);
|
||||
gradient.variantProperty("focalRadius").setValue(0);
|
||||
|
||||
} else if (m_gradientTypeName == "ConicalGradient") {
|
||||
qreal width = m_itemNode.instanceValue("width").toReal();
|
||||
qreal height = m_itemNode.instanceValue("height").toReal();
|
||||
gradient.variantProperty("centerX").setValue(width / 2.0);
|
||||
gradient.variantProperty("centerY").setValue(height / 2.0);
|
||||
|
||||
gradient.variantProperty("angle").setValue(0);
|
||||
} else if (m_gradientTypeName == u"LinearGradient") {
|
||||
std::for_each(std::begin(defaultLinearShapeGradients),
|
||||
std::end(defaultLinearShapeGradients),
|
||||
[&](auto &a) {
|
||||
gradient.variantProperty(a.name.toByteArray())
|
||||
.setValue(a.getDefaultValue(m_itemNode));
|
||||
});
|
||||
} else if (m_gradientTypeName == u"RadialGradient") {
|
||||
std::for_each(std::begin(defaultRadialShapeGradients),
|
||||
std::end(defaultRadialShapeGradients),
|
||||
[&](auto &a) {
|
||||
gradient.variantProperty(a.name.toByteArray())
|
||||
.setValue(a.getDefaultValue(m_itemNode));
|
||||
});
|
||||
} else if (m_gradientTypeName == u"ConicalGradient") {
|
||||
std::for_each(std::begin(defaultConicalShapeGradients),
|
||||
std::end(defaultConicalShapeGradients),
|
||||
[&](auto &a) {
|
||||
gradient.variantProperty(a.name.toByteArray())
|
||||
.setValue(a.getDefaultValue(m_itemNode));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,7 +625,7 @@ void GradientModel::resetPuppet()
|
||||
|
||||
QmlDesigner::ModelNode GradientModel::createGradientNode()
|
||||
{
|
||||
QByteArray fullTypeName = m_gradientTypeName.toUtf8();
|
||||
QmlDesigner::TypeName fullTypeName = m_gradientTypeName.toUtf8();
|
||||
|
||||
if (m_gradientTypeName == "Gradient") {
|
||||
fullTypeName.prepend("QtQuick.");
|
||||
@@ -489,24 +664,115 @@ void GradientModel::deleteGradientNode(bool saveTransaction)
|
||||
if (modelNode.hasProperty(gradientPropertyName().toUtf8())) {
|
||||
QmlDesigner::RewriterTransaction transaction;
|
||||
if (saveTransaction)
|
||||
transaction = view()->beginRewriterTransaction(QByteArrayLiteral("GradientModel::deleteGradient"));
|
||||
transaction = view()->beginRewriterTransaction(
|
||||
QByteArrayLiteral("GradientModel::deleteGradient"));
|
||||
|
||||
QmlDesigner::ModelNode gradientNode
|
||||
= modelNode.nodeProperty(gradientPropertyName().toUtf8()).modelNode();
|
||||
if (QmlDesigner::QmlObjectNode(gradientNode).isValid())
|
||||
QmlDesigner::QmlObjectNode(gradientNode).destroy();
|
||||
QmlDesigner::QmlObjectNode gradientNode = modelNode
|
||||
.nodeProperty(gradientPropertyName().toUtf8())
|
||||
.modelNode();
|
||||
if (gradientNode.isValid())
|
||||
gradientNode.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GradientModel::hasPercentageGradientProperty(const QString &propertyName) const
|
||||
{
|
||||
bool result = false;
|
||||
getPercentageGradientProperty(propertyName.toUtf8(), &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
qreal GradientModel::getPercentageGradientProperty(const QmlDesigner::PropertyNameView propertyName,
|
||||
bool *ok) const
|
||||
{
|
||||
if (ok != nullptr)
|
||||
*ok = false;
|
||||
|
||||
if (!m_itemNode.isValid())
|
||||
return 0.;
|
||||
|
||||
//valid format is itemName1.property * 0.1
|
||||
//we are interested in parent. or parentName. items
|
||||
//and in width and height properties as of now
|
||||
//looking for something that starts with "itemName1.property"
|
||||
//looking for something like "* 0.223"
|
||||
const QmlDesigner::TypeName gradientPropertyTypeName = gradientPropertyName().toUtf8();
|
||||
|
||||
const QmlDesigner::ModelNode gradientModel = m_itemNode.modelNode()
|
||||
.nodeProperty(gradientPropertyTypeName)
|
||||
.modelNode();
|
||||
|
||||
if (!gradientModel)
|
||||
return 0.;
|
||||
|
||||
if (const auto bindingProperty = gradientModel.bindingProperty(propertyName.toByteArray())) {
|
||||
const auto defaultGradient = getDefaultGradientPropertyData(propertyName, m_gradientTypeName);
|
||||
const auto expectedParentProperty = defaultGradient.bindingProperty;
|
||||
|
||||
const QString expression = bindingProperty.expression();
|
||||
const QStringList splitExpression = expression.split("*", Qt::SkipEmptyParts);
|
||||
if (splitExpression.length() == 2 && !expectedParentProperty.isEmpty()) {
|
||||
const QString parentStr = splitExpression.at(0).trimmed();
|
||||
const QString percentageStr = splitExpression.at(1).trimmed();
|
||||
|
||||
bool validStatement = false;
|
||||
|
||||
if (!parentStr.isEmpty()) {
|
||||
const QStringList splitParent = parentStr.split(".", Qt::SkipEmptyParts);
|
||||
if (splitParent.length() == 2) {
|
||||
const QString itemId = splitParent.at(0).trimmed();
|
||||
const QString itemProp = splitParent.at(1).trimmed();
|
||||
const QString realParentId = m_itemNode.modelNode().hasId() ? m_itemNode.id() : "";
|
||||
if (!itemId.isEmpty() && !itemProp.isEmpty() && (itemId == realParentId)
|
||||
&& (itemProp.toUtf8() == expectedParentProperty)) {
|
||||
validStatement = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!percentageStr.isEmpty() && validStatement) {
|
||||
const qreal percentage = percentageStr.toFloat(ok);
|
||||
return percentage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0.;
|
||||
}
|
||||
|
||||
QVariant GradientModel::getGradientPropertyVariant(const QString &propertyName) const
|
||||
{
|
||||
if (!m_itemNode.isValid())
|
||||
return {};
|
||||
|
||||
QmlDesigner::QmlObjectNode gradient = m_itemNode.modelNode()
|
||||
.nodeProperty(gradientPropertyName().toUtf8())
|
||||
.modelNode();
|
||||
|
||||
if (!gradient.isValid())
|
||||
return {};
|
||||
|
||||
return gradient.modelValue(propertyName.toUtf8());
|
||||
}
|
||||
|
||||
ShapeGradientPropertyData GradientModel::getDefaultGradientPropertyData(
|
||||
const QmlDesigner::PropertyNameView propertyName, const QStringView &gradientType) const
|
||||
{
|
||||
const auto *gradData = getDefaultGradientData(propertyName, gradientType);
|
||||
if (gradData != nullptr)
|
||||
return *gradData;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void GradientModel::setGradientProperty(const QString &propertyName, qreal value)
|
||||
{
|
||||
QTC_ASSERT(m_itemNode.isValid(), return);
|
||||
|
||||
QmlDesigner::QmlObjectNode gradient;
|
||||
|
||||
if (m_itemNode.modelNode().hasProperty(gradientPropertyName().toUtf8()))
|
||||
gradient = m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).modelNode();
|
||||
QmlDesigner::QmlObjectNode gradient = m_itemNode.modelNode()
|
||||
.nodeProperty(gradientPropertyName().toUtf8())
|
||||
.modelNode();
|
||||
|
||||
QTC_ASSERT(gradient.isValid(), return);
|
||||
|
||||
@@ -517,14 +783,47 @@ void GradientModel::setGradientProperty(const QString &propertyName, qreal value
|
||||
}
|
||||
}
|
||||
|
||||
void GradientModel::setGradientPropertyPercentage(const QString &propertyName, qreal value)
|
||||
{
|
||||
QTC_ASSERT(m_itemNode.isValid(), return);
|
||||
|
||||
QmlDesigner::QmlObjectNode gradient = m_itemNode.modelNode()
|
||||
.nodeProperty(gradientPropertyName().toUtf8())
|
||||
.modelNode();
|
||||
|
||||
QTC_ASSERT(gradient.isValid(), return);
|
||||
|
||||
const auto gradientDefaultData = getDefaultGradientPropertyData(propertyName.toUtf8(),
|
||||
m_gradientTypeName);
|
||||
QTC_ASSERT(gradientDefaultData.canUsePercentage == ShapeGradientPropertyData::UsePercents::Yes,
|
||||
return);
|
||||
|
||||
const QmlDesigner::PropertyNameView parentPropertyStr = gradientDefaultData.bindingProperty;
|
||||
QTC_ASSERT(!parentPropertyStr.isEmpty(), return);
|
||||
|
||||
if (parentPropertyStr.isEmpty()
|
||||
|| (gradientDefaultData.canUsePercentage == ShapeGradientPropertyData::UsePercents::No)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString parentId = m_itemNode.validId();
|
||||
const QString leftBinding = parentId + "." + parentPropertyStr;
|
||||
const QString expression = leftBinding + " * " + QString::number(value);
|
||||
|
||||
try {
|
||||
gradient.setBindingProperty(propertyName.toUtf8(), expression);
|
||||
} catch (const QmlDesigner::Exception &e) {
|
||||
e.showException();
|
||||
}
|
||||
}
|
||||
|
||||
void GradientModel::setGradientOrientation(Qt::Orientation value)
|
||||
{
|
||||
QTC_ASSERT(m_itemNode.isValid(), return);
|
||||
|
||||
QmlDesigner::QmlObjectNode gradient;
|
||||
|
||||
if (m_itemNode.modelNode().hasProperty(gradientPropertyName().toUtf8()))
|
||||
gradient = m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).modelNode();
|
||||
QmlDesigner::QmlObjectNode gradient = m_itemNode.modelNode()
|
||||
.nodeProperty(gradientPropertyName().toUtf8())
|
||||
.modelNode();
|
||||
|
||||
QTC_ASSERT(gradient.isValid(), return);
|
||||
|
||||
@@ -537,6 +836,56 @@ void GradientModel::setGradientOrientation(Qt::Orientation value)
|
||||
}
|
||||
}
|
||||
|
||||
void GradientModel::setGradientPropertyUnits(const QString &propertyName,
|
||||
GradientModel::GradientPropertyUnits value)
|
||||
{
|
||||
//translate from previous units to the new unit system
|
||||
const bool toPixels = (value == GradientPropertyUnits::Pixels);
|
||||
const bool toPercentage = (value == GradientPropertyUnits::Percentage);
|
||||
const auto defaultGradientData = getDefaultGradientPropertyData(propertyName.toUtf8(),
|
||||
m_gradientTypeName);
|
||||
|
||||
const QmlDesigner::PropertyNameView parentPropertyName = defaultGradientData.bindingProperty;
|
||||
if (parentPropertyName.isEmpty())
|
||||
return;
|
||||
|
||||
const qreal parentPropertyValue = m_itemNode.instanceValue(parentPropertyName.toByteArray()).toReal();
|
||||
|
||||
if (toPixels) {
|
||||
bool ok = false;
|
||||
const qreal percent = getPercentageGradientProperty(propertyName.toUtf8(), &ok);
|
||||
qreal pixelValue = 0.;
|
||||
|
||||
if (!ok)
|
||||
pixelValue = defaultGradientData.getDefaultValue(m_itemNode);
|
||||
else
|
||||
pixelValue = parentPropertyValue * percent;
|
||||
|
||||
if (qIsNaN(pixelValue) || qIsInf(pixelValue))
|
||||
pixelValue = 0.;
|
||||
|
||||
setGradientProperty(propertyName, qRound(pixelValue));
|
||||
} else if (toPercentage) {
|
||||
const QVariant gradientProp = getGradientPropertyVariant(propertyName);
|
||||
bool ok = false;
|
||||
qreal pixels = gradientProp.toReal(&ok);
|
||||
qreal percentValue = 0.;
|
||||
|
||||
if (gradientProp.isNull() || !gradientProp.isValid() || !ok)
|
||||
pixels = defaultGradientData.getDefaultValue(m_itemNode);
|
||||
|
||||
if (qFuzzyIsNull(pixels) || qFuzzyIsNull(parentPropertyValue))
|
||||
percentValue = 0.;
|
||||
else
|
||||
percentValue = (pixels / parentPropertyValue);
|
||||
|
||||
if (qIsNaN(percentValue) || qIsInf(percentValue))
|
||||
percentValue = 0.;
|
||||
|
||||
setGradientPropertyPercentage(propertyName, percentValue);
|
||||
}
|
||||
}
|
||||
|
||||
void GradientModel::setPresetByID(int presetID)
|
||||
{
|
||||
const QGradient gradient(GradientPresetItem::createGradientFromPreset(
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <QtQml>
|
||||
#include <enumeration.h>
|
||||
|
||||
class ShapeGradientPropertyData;
|
||||
|
||||
class GradientModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -45,11 +47,21 @@ public:
|
||||
|
||||
static void registerDeclarativeType();
|
||||
|
||||
Q_INVOKABLE qreal readGradientProperty(const QString &property) const;
|
||||
enum GradientPropertyUnits { Pixels = 0, Percentage = 1 };
|
||||
Q_ENUM(GradientPropertyUnits)
|
||||
|
||||
Q_INVOKABLE qreal readGradientProperty(const QString &propertyName) const;
|
||||
Q_INVOKABLE qreal readGradientPropertyPercentage(const QString &propertyName) const;
|
||||
Q_INVOKABLE QString readGradientOrientation() const;
|
||||
Q_INVOKABLE GradientPropertyUnits readGradientPropertyUnits(const QString &propertyName) const;
|
||||
Q_INVOKABLE bool isPercentageSupportedByProperty(const QString &propertyName,
|
||||
const QString &gradientTypeName) const;
|
||||
|
||||
Q_INVOKABLE void setGradientProperty(const QString &propertyName, qreal value);
|
||||
Q_INVOKABLE void setGradientPropertyPercentage(const QString &propertyName, qreal value);
|
||||
Q_INVOKABLE void setGradientOrientation(Qt::Orientation value);
|
||||
Q_INVOKABLE void setGradientPropertyUnits(const QString &propertyName,
|
||||
GradientModel::GradientPropertyUnits value);
|
||||
|
||||
Q_INVOKABLE void setPresetByID(int presetID);
|
||||
Q_INVOKABLE void setPresetByStops(const QList<qreal> &stopsPositions,
|
||||
@@ -81,6 +93,15 @@ private:
|
||||
QmlDesigner::ModelNode createGradientStopNode();
|
||||
void deleteGradientNode(bool saveTransaction);
|
||||
|
||||
bool hasPercentageGradientProperty(const QString &propertyName) const;
|
||||
qreal getPercentageGradientProperty(const QmlDesigner::PropertyNameView propertyName,
|
||||
bool *ok = nullptr) const;
|
||||
|
||||
QVariant getGradientPropertyVariant(const QString &propertyName) const;
|
||||
|
||||
ShapeGradientPropertyData getDefaultGradientPropertyData(
|
||||
const QmlDesigner::PropertyNameView propertyName, const QStringView &gradientType) const;
|
||||
|
||||
private:
|
||||
QmlDesigner::QmlItemNode m_itemNode;
|
||||
QString m_gradientPropertyName;
|
||||
|
||||
Reference in New Issue
Block a user