diff --git a/PropertyEditor/resources.qrc b/PropertyEditor/resources.qrc
index 55b790d..0a0e6cc 100644
--- a/PropertyEditor/resources.qrc
+++ b/PropertyEditor/resources.qrc
@@ -23,5 +23,9 @@
resources/Qml/ValueEditor/FileSelector.qml
resources/Qml/ValueEditor/LineTextBox.qml
resources/Qml/ValueEditor/MultiLineTextBox.qml
+ resources/Qml/ValueEditor/PointFBox.qml
+ resources/Qml/ValueEditor/RectFBox.qml
+ resources/Qml/ValueEditor/SizeFBox.qml
+ resources/Qml/ValueEditor/BoolBox.qml
diff --git a/PropertyEditor/resources/Qml/ValueEditor/BoolBox.qml b/PropertyEditor/resources/Qml/ValueEditor/BoolBox.qml
new file mode 100644
index 0000000..828f24a
--- /dev/null
+++ b/PropertyEditor/resources/Qml/ValueEditor/BoolBox.qml
@@ -0,0 +1,184 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuick.Shapes
+
+Item {
+ id: control
+
+ // 保持与框架一致的接口
+ property var value: false
+ property int decimals: 0
+ property string text: "Enabled"
+ property color textColor: "black"
+ property color checkedColor: "#2196F3"
+ property color uncheckedColor: "#cccccc"
+ property color checkedBoxColor: "white"
+ property color uncheckedBoxColor: "white"
+ property int boxSize: 16
+ property int spacing: 8
+ property int textSize: 12
+ property alias font: label.font
+
+ // 与框架一致的信号
+ signal asValueChanged(value: var)
+ signal boolValueChanged(bool checked) // 辅助信号,避免与内置信号冲突
+
+ implicitHeight: Math.max(boxSize, label.implicitHeight)
+ implicitWidth: boxSize + spacing + label.implicitWidth
+
+ function toggle() {
+ var newValue = !getBoolValue()
+ setValue(newValue)
+ }
+
+ function setValue(newValue) {
+ var boolValue = getBoolValue()
+ var newBoolValue = toBool(newValue)
+
+ if (boolValue !== newBoolValue) {
+ value = newBoolValue
+ boolValueChanged(newBoolValue)
+ asValueChanged(newBoolValue)
+ }
+ }
+
+ function getBoolValue() {
+ return toBool(value)
+ }
+
+ function toBool(value) {
+ if (typeof value === 'boolean') {
+ return value
+ } else if (typeof value === 'number') {
+ return value !== 0
+ } else if (typeof value === 'string') {
+ var str = value.toString().toLowerCase()
+ return str === 'true' || str === '1' || str === 'on'
+ }
+ return false
+ }
+
+ // 整个区域的点击事件
+ MouseArea {
+ anchors.fill: parent
+
+ onClicked: function(mouse) {
+ control.toggle()
+ mouse.accepted = true
+ }
+ }
+
+ RowLayout {
+ anchors.fill: parent
+ spacing: control.spacing
+
+ // 复选框
+ Rectangle {
+ id: checkBox
+ width: control.boxSize
+ height: control.boxSize
+ radius: 3
+ border.color: getBoolValue() ? control.checkedColor : control.uncheckedColor
+ border.width: 1
+ color: getBoolValue() ? control.checkedColor : control.uncheckedBoxColor
+
+ Layout.alignment: Qt.AlignVCenter
+
+ // 勾选标记
+ Shape {
+ anchors.centerIn: parent
+ width: 10
+ height: 8
+ visible: getBoolValue()
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillColor: control.checkedBoxColor
+ strokeWidth: 0
+
+ PathMove { x: 0; y: 4 }
+ PathLine { x: 4; y: 8 }
+ PathLine { x: 10; y: 0 }
+ PathLine { x: 9; y: 0 }
+ PathLine { x: 4; y: 7 }
+ PathLine { x: 1; y: 4 }
+ }
+ }
+
+ // 悬停效果
+ Rectangle {
+ anchors.fill: parent
+ radius: parent.radius
+ color: "transparent"
+ border.color: "#888888"
+ border.width: boxMouseArea.containsMouse ? 1 : 0
+ opacity: boxMouseArea.containsMouse ? 0.3 : 0
+ }
+
+ // 复选框自身的点击事件
+ MouseArea {
+ id: boxMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+
+ onClicked: function(mouse) {
+ control.toggle()
+ mouse.accepted = true
+ }
+ }
+ }
+
+ // 标签文本
+ Label {
+ id: label
+ text: control.text
+ color: control.textColor
+ font.pixelSize: control.textSize
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.alignment: Qt.AlignVCenter
+ Layout.fillWidth: true
+
+ // 鼠标悬停在文本上时的点击事件
+ MouseArea {
+ anchors.fill: parent
+
+ onClicked: function(mouse) {
+ control.toggle()
+ mouse.accepted = true
+ }
+ }
+ }
+ }
+
+ // 键盘支持
+ Keys.onPressed: function(event) {
+ if (event.key === Qt.Key_Space || event.key === Qt.Key_Return) {
+ control.toggle()
+ event.accepted = true
+ }
+ }
+
+ // 聚焦支持
+ activeFocusOnTab: true
+
+ // 聚焦时的边框
+ Rectangle {
+ anchors.fill: parent
+ color: "transparent"
+ border.color: control.activeFocus ? "#2196F3" : "transparent"
+ border.width: 2
+ radius: 2
+ visible: control.activeFocus
+ }
+
+ // 当value从外部改变时,更新显示
+ onValueChanged: {
+ var boolValue = getBoolValue()
+ if (checkBox.border.color !== (boolValue ? control.checkedColor : control.uncheckedColor)) {
+ checkBox.border.color = boolValue ? control.checkedColor : control.uncheckedColor
+ checkBox.color = boolValue ? control.checkedColor : control.uncheckedBoxColor
+ }
+ }
+}
diff --git a/PropertyEditor/resources/Qml/ValueEditor/PointFBox.qml b/PropertyEditor/resources/Qml/ValueEditor/PointFBox.qml
new file mode 100644
index 0000000..c323fbe
--- /dev/null
+++ b/PropertyEditor/resources/Qml/ValueEditor/PointFBox.qml
@@ -0,0 +1,184 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+Item {
+ id: control
+
+ property var value: Qt.point(0, 0)
+ property int decimals: 2
+ implicitHeight: 25
+ implicitWidth: 120 // 设置默认宽度
+
+ signal asValueChanged(value: var)
+
+ function setValue(newValue: var) {
+ if (!control.value ||
+ Math.abs(control.value.x - newValue.x) > 0.000001 ||
+ Math.abs(control.value.y - newValue.y) > 0.000001) {
+ value = newValue
+ asValueChanged(value)
+ }
+ }
+
+ RowLayout {
+ anchors.fill: parent
+ spacing: 4 // 减小间距
+
+ Label {
+ text: "X:"
+ Layout.alignment: Qt.AlignVCenter
+ font.pixelSize: 10
+ }
+
+ TextField {
+ id: xBox
+ Layout.preferredWidth: 60 // 减小宽度
+ Layout.preferredHeight: 22
+ Layout.alignment: Qt.AlignVCenter
+ text: control.value ? control.value.x.toFixed(control.decimals) : "0.00"
+ font.pixelSize: 10
+ leftPadding: 4
+ rightPadding: 4
+ selectByMouse: true
+
+ // 双击全选的处理
+ MouseArea {
+ id: xMouseArea
+ anchors.fill: parent
+ propagateComposedEvents: true
+ acceptedButtons: Qt.LeftButton
+ cursorShape: Qt.IBeamCursor
+
+ onDoubleClicked: function(mouse) {
+ parent.selectAll()
+ parent.forceActiveFocus()
+ mouse.accepted = true
+ }
+
+ onClicked: function(mouse) {
+ // 单击时设置焦点但不全选
+ parent.forceActiveFocus()
+ mouse.accepted = false
+ }
+ }
+
+ onActiveFocusChanged: {
+ if (activeFocus) {
+ // 如果不是双击触发的焦点变化,就全选文本
+ if (!xMouseArea.containsPress) {
+ selectAll()
+ }
+ }
+ }
+
+ validator: DoubleValidator {
+ bottom: -999999
+ top: 999999
+ decimals: 2
+ }
+
+ background: Rectangle {
+ color: xBox.enabled ? "white" : "#f0f0f0"
+ border.color: xBox.activeFocus ? "#2196F3" : "#cccccc"
+ border.width: 1
+ radius: 2
+ }
+
+ onEditingFinished: {
+ var xValue = parseFloat(text)
+ if (!isNaN(xValue) && control.value) {
+ control.setValue(Qt.point(xValue, control.value.y))
+ } else {
+ xBox.text = control.value ? control.value.x.toFixed(control.decimals) : "0.00"
+ }
+ }
+ }
+
+ Label {
+ text: "Y:"
+ Layout.alignment: Qt.AlignVCenter
+ font.pixelSize: 10
+ }
+
+ TextField {
+ id: yBox
+ Layout.preferredWidth: 60
+ Layout.preferredHeight: 22
+ Layout.alignment: Qt.AlignVCenter
+ text: control.value ? control.value.y.toFixed(control.decimals) : "0.00"
+ font.pixelSize: 10
+ leftPadding: 4
+ rightPadding: 4
+ selectByMouse: true
+
+ // 双击全选的处理
+ MouseArea {
+ id: yMouseArea
+ anchors.fill: parent
+ propagateComposedEvents: true
+ acceptedButtons: Qt.LeftButton
+ cursorShape: Qt.IBeamCursor
+
+ onDoubleClicked: function(mouse) {
+ parent.selectAll()
+ parent.forceActiveFocus()
+ mouse.accepted = true
+ }
+
+ onClicked: function(mouse) {
+ // 单击时设置焦点但不全选
+ parent.forceActiveFocus()
+ mouse.accepted = false
+ }
+ }
+
+ onActiveFocusChanged: {
+ if (activeFocus) {
+ // 如果不是双击触发的焦点变化,就全选文本
+ if (!yMouseArea.containsPress) {
+ selectAll()
+ }
+ }
+ }
+
+ validator: DoubleValidator {
+ bottom: -999999
+ top: 999999
+ decimals: 2
+ }
+
+ background: Rectangle {
+ color: yBox.enabled ? "white" : "#f0f0f0"
+ border.color: yBox.activeFocus ? "#2196F3" : "#cccccc"
+ border.width: 1
+ radius: 2
+ }
+
+ onEditingFinished: {
+ var yValue = parseFloat(text)
+ if (!isNaN(yValue) && control.value) {
+ control.setValue(Qt.point(control.value.x, yValue))
+ } else {
+ yBox.text = control.value ? control.value.y.toFixed(control.decimals) : "0.00"
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+ }
+
+ // 当value从外部改变时,更新输入框显示
+ onValueChanged: {
+ if (value) {
+ if (!xBox.activeFocus) {
+ xBox.text = value.x.toFixed(decimals)
+ }
+ if (!yBox.activeFocus) {
+ yBox.text = value.y.toFixed(decimals)
+ }
+ }
+ }
+}
diff --git a/PropertyEditor/resources/Qml/ValueEditor/RectFBox.qml b/PropertyEditor/resources/Qml/ValueEditor/RectFBox.qml
new file mode 100644
index 0000000..e194763
--- /dev/null
+++ b/PropertyEditor/resources/Qml/ValueEditor/RectFBox.qml
@@ -0,0 +1,136 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+Item {
+ id: control
+
+ property var value: Qt.rect(0, 0, 0, 0)
+ property int decimals: 1
+ implicitHeight: 25
+ implicitWidth: 240
+
+ signal asValueChanged(value: var)
+
+ function setValue(newValue) {
+ if (!control.value ||
+ Math.abs(control.value.x - newValue.x) > 0.000001 ||
+ Math.abs(control.value.y - newValue.y) > 0.000001 ||
+ Math.abs(control.value.width - newValue.width) > 0.000001 ||
+ Math.abs(control.value.height - newValue.height) > 0.000001) {
+ value = newValue
+ asValueChanged(value)
+ }
+ }
+
+ RowLayout {
+ anchors.fill: parent
+ spacing: 2
+
+ Repeater {
+ id: repeater
+ model: [
+ { label: "X", prop: "x", validator: [-999999, 999999] },
+ { label: "Y", prop: "y", validator: [-999999, 999999] },
+ { label: "W", prop: "width", validator: [0, 999999] },
+ { label: "H", prop: "height", validator: [0, 999999] }
+ ]
+
+ RowLayout {
+ id: inputRow
+ spacing: 2
+ Layout.alignment: Qt.AlignVCenter
+
+ property string propertyName: modelData.prop
+ property var textField: inputField
+
+ Label {
+ text: modelData.label + ":"
+ font.pixelSize: 10
+ }
+
+ TextField {
+ id: inputField
+ Layout.preferredWidth: 60
+ Layout.preferredHeight: 22
+ text: control.value ? control.value[modelData.prop].toFixed(control.decimals) : "0.0"
+ font.pixelSize: 9
+ padding: 2
+ selectByMouse: true
+
+ // 双击全选的处理
+ MouseArea {
+ id: fieldMouseArea
+ anchors.fill: parent
+ propagateComposedEvents: true
+ acceptedButtons: Qt.LeftButton
+ cursorShape: Qt.IBeamCursor
+
+ onDoubleClicked: function(mouse) {
+ parent.selectAll()
+ parent.forceActiveFocus()
+ mouse.accepted = true
+ }
+
+ onClicked: function(mouse) {
+ // 单击时设置焦点但不全选
+ parent.forceActiveFocus()
+ mouse.accepted = false
+ }
+ }
+
+ onActiveFocusChanged: {
+ if (activeFocus) {
+ // 如果不是双击触发的焦点变化,就全选文本
+ if (!fieldMouseArea.containsPress) {
+ selectAll()
+ }
+ }
+ }
+
+ validator: DoubleValidator {
+ bottom: modelData.validator[0]
+ top: modelData.validator[1]
+ decimals: 2
+ }
+
+ background: Rectangle {
+ border.color: parent.activeFocus ? "#0066cc" : "#999999"
+ border.width: 1
+ radius: 1
+ }
+
+ onEditingFinished: {
+ var val = parseFloat(text)
+ if (!isNaN(val) && control.value) {
+ var newRect = Qt.rect(
+ modelData.prop === "x" ? val : control.value.x,
+ modelData.prop === "y" ? val : control.value.y,
+ modelData.prop === "width" ? val : control.value.width,
+ modelData.prop === "height" ? val : control.value.height
+ )
+ control.setValue(newRect)
+ } else {
+ text = control.value ? control.value[modelData.prop].toFixed(control.decimals) : "0.0"
+ }
+ }
+ }
+ }
+ }
+
+ Item { Layout.fillWidth: true }
+ }
+
+ onValueChanged: {
+ if (!value) return
+
+ // 通过 Repeater 的 itemAt 方法安全访问
+ var props = ["x", "y", "width", "height"]
+ for (var i = 0; i < props.length; i++) {
+ var item = repeater.itemAt(i)
+ if (item && item.textField && !item.textField.activeFocus) {
+ item.textField.text = value[props[i]].toFixed(decimals)
+ }
+ }
+ }
+}
diff --git a/PropertyEditor/resources/Qml/ValueEditor/SizeFBox.qml b/PropertyEditor/resources/Qml/ValueEditor/SizeFBox.qml
new file mode 100644
index 0000000..ce347cc
--- /dev/null
+++ b/PropertyEditor/resources/Qml/ValueEditor/SizeFBox.qml
@@ -0,0 +1,372 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+Item {
+ id: control
+
+ // 属性定义
+ property var value: Qt.size(0, 0) // QSizeF
+ property int decimals: 1 // 默认小数位为1
+ property int precision: 2 // 精度,允许的小数位数
+
+ // 尺寸相关属性
+ property real minWidth: 0
+ property real maxWidth: 999999
+ property real minHeight: 0
+ property real maxHeight: 999999
+
+ // 步进增量
+ property real widthStep: 1.0
+ property real heightStep: 1.0
+
+ // 是否显示步进按钮
+ property bool showSpinButtons: true
+
+ implicitHeight: 25
+ implicitWidth: showSpinButtons ? 140 : 120
+
+ // 信号 - 重命名避免与内置信号冲突
+ signal asValueChanged(value: var)
+ signal sizeWidthChanged(width: real) // 改为 sizeWidthChanged
+ signal sizeHeightChanged(height: real) // 改为 sizeHeightChanged
+
+ // 获取宽高
+ function getWidth() {
+ return value ? value.width : 0
+ }
+
+ function getHeight() {
+ return value ? value.height : 0
+ }
+
+ // 设置值
+ function setValue(newValue: var) {
+ if (!control.value ||
+ Math.abs(control.value.width - newValue.width) > 0.000001 ||
+ Math.abs(control.value.height - newValue.height) > 0.000001) {
+
+ // 应用边界限制
+ var limitedWidth = Math.max(minWidth, Math.min(maxWidth, newValue.width))
+ var limitedHeight = Math.max(minHeight, Math.min(maxHeight, newValue.height))
+
+ // 保留精度
+ limitedWidth = parseFloat(limitedWidth.toFixed(precision))
+ limitedHeight = parseFloat(limitedHeight.toFixed(precision))
+
+ value = Qt.size(limitedWidth, limitedHeight)
+ asValueChanged(value)
+ }
+ }
+
+ // 设置宽度
+ function setWidth(width: real) {
+ if (control.value && Math.abs(control.value.width - width) > 0.000001) {
+ var limitedWidth = Math.max(minWidth, Math.min(maxWidth, width))
+ limitedWidth = parseFloat(limitedWidth.toFixed(precision))
+ control.setValue(Qt.size(limitedWidth, control.value.height))
+ }
+ }
+
+ // 设置高度
+ function setHeight(height: real) {
+ if (control.value && Math.abs(control.value.height - height) > 0.000001) {
+ var limitedHeight = Math.max(minHeight, Math.min(maxHeight, height))
+ limitedHeight = parseFloat(limitedHeight.toFixed(precision))
+ control.setValue(Qt.size(control.value.width, limitedHeight))
+ }
+ }
+
+ // 步进增加/减少
+ function stepWidth(positive: bool) {
+ if (!control.value) return
+ var step = positive ? widthStep : -widthStep
+ setWidth(getWidth() + step)
+ }
+
+ function stepHeight(positive: bool) {
+ if (!control.value) return
+ var step = positive ? heightStep : -heightStep
+ setHeight(getHeight() + step)
+ }
+
+ // UI布局
+ RowLayout {
+ anchors.fill: parent
+ spacing: 4
+
+ // 宽度部分
+ Label {
+ text: "W:"
+ Layout.alignment: Qt.AlignVCenter
+ font.pixelSize: 10
+ }
+
+ TextField {
+ id: widthBox
+ Layout.preferredWidth: 60
+ Layout.preferredHeight: 22
+ Layout.alignment: Qt.AlignVCenter
+ selectByMouse: true // 允许鼠标选择文本
+
+ text: control.value ? control.value.width.toFixed(control.decimals) : "0.0"
+ font.pixelSize: 10
+ leftPadding: 4
+ rightPadding: 4
+
+ // 双击全选的处理
+ MouseArea {
+ id: widthMouseArea
+ anchors.fill: parent
+ propagateComposedEvents: true
+ acceptedButtons: Qt.LeftButton
+ cursorShape: Qt.IBeamCursor
+
+ onDoubleClicked: function(mouse) {
+ parent.selectAll()
+ parent.forceActiveFocus()
+ mouse.accepted = true
+ }
+
+ onClicked: function(mouse) {
+ // 单击时设置焦点但不全选
+ parent.forceActiveFocus()
+ mouse.accepted = false
+ }
+ }
+
+ onActiveFocusChanged: {
+ if (activeFocus) {
+ // 如果不是双击触发的焦点变化,就全选文本
+ if (!widthMouseArea.containsPress) {
+ selectAll()
+ }
+ }
+ }
+
+ // 验证器
+ validator: DoubleValidator {
+ bottom: control.minWidth
+ top: control.maxWidth
+ decimals: control.precision
+ notation: DoubleValidator.StandardNotation
+ }
+
+ background: Rectangle {
+ color: widthBox.enabled ? "white" : "#f0f0f0"
+ border.color: widthBox.activeFocus ? "#2196F3" : "#cccccc"
+ border.width: 1
+ radius: 2
+ }
+
+ onEditingFinished: {
+ var num = parseFloat(text)
+ if (!isNaN(num) && control.value) {
+ control.setWidth(num)
+ } else {
+ // 恢复原值
+ widthBox.text = control.value ?
+ control.value.width.toFixed(control.decimals) :
+ "0.0"
+ }
+ }
+
+ // 键盘上下键调整
+ Keys.onUpPressed: function(event) {
+ control.stepWidth(true)
+ event.accepted = true
+ }
+
+ Keys.onDownPressed: function(event) {
+ control.stepWidth(false)
+ event.accepted = true
+ }
+ }
+
+ // 宽度步进按钮
+ Row {
+ visible: control.showSpinButtons
+ spacing: 0
+ Layout.alignment: Qt.AlignVCenter
+
+ Button {
+ width: 12
+ height: 11
+ text: "▲"
+ font.pixelSize: 6
+ padding: 0
+ onClicked: control.stepWidth(true)
+
+ background: Rectangle {
+ color: parent.hovered ? "#e0e0e0" : "transparent"
+ border.color: "#cccccc"
+ border.width: 1
+ radius: 2
+ }
+ }
+
+ Button {
+ width: 12
+ height: 11
+ text: "▼"
+ font.pixelSize: 6
+ padding: 0
+ onClicked: control.stepWidth(false)
+
+ background: Rectangle {
+ color: parent.hovered ? "#e0e0e0" : "transparent"
+ border.color: "#cccccc"
+ border.width: 1
+ radius: 2
+ }
+ }
+ }
+
+ // 高度部分
+ Label {
+ text: "H:"
+ Layout.alignment: Qt.AlignVCenter
+ font.pixelSize: 10
+ }
+
+ TextField {
+ id: heightBox
+ Layout.preferredWidth: 60
+ Layout.preferredHeight: 22
+ Layout.alignment: Qt.AlignVCenter
+ selectByMouse: true // 允许鼠标选择文本
+
+ text: control.value ? control.value.height.toFixed(control.decimals) : "0.0"
+ font.pixelSize: 10
+ leftPadding: 4
+ rightPadding: 4
+
+ // 双击全选的处理
+ MouseArea {
+ id: heightMouseArea
+ anchors.fill: parent
+ propagateComposedEvents: true
+ acceptedButtons: Qt.LeftButton
+ cursorShape: Qt.IBeamCursor
+
+ onDoubleClicked: function(mouse) {
+ parent.selectAll()
+ parent.forceActiveFocus()
+ mouse.accepted = true
+ }
+
+ onClicked: function(mouse) {
+ // 单击时设置焦点但不全选
+ parent.forceActiveFocus()
+ mouse.accepted = false
+ }
+ }
+
+ onActiveFocusChanged: {
+ if (activeFocus) {
+ // 如果不是双击触发的焦点变化,就全选文本
+ if (!heightMouseArea.containsPress) {
+ selectAll()
+ }
+ }
+ }
+
+ // 验证器
+ validator: DoubleValidator {
+ bottom: control.minHeight
+ top: control.maxHeight
+ decimals: control.precision
+ notation: DoubleValidator.StandardNotation
+ }
+
+ background: Rectangle {
+ color: heightBox.enabled ? "white" : "#f0f0f0"
+ border.color: heightBox.activeFocus ? "#2196F3" : "#cccccc"
+ border.width: 1
+ radius: 2
+ }
+
+ onEditingFinished: {
+ var num = parseFloat(text)
+ if (!isNaN(num) && control.value) {
+ control.setHeight(num)
+ } else {
+ // 恢复原值
+ heightBox.text = control.value ?
+ control.value.height.toFixed(control.decimals) :
+ "0.0"
+ }
+ }
+
+ // 键盘上下键调整
+ Keys.onUpPressed: function(event) {
+ control.stepHeight(true)
+ event.accepted = true
+ }
+
+ Keys.onDownPressed: function(event) {
+ control.stepHeight(false)
+ event.accepted = true
+ }
+ }
+
+ // 高度步进按钮
+ Row {
+ visible: control.showSpinButtons
+ spacing: 0
+ Layout.alignment: Qt.AlignVCenter
+
+ Button {
+ width: 12
+ height: 11
+ text: "▲"
+ font.pixelSize: 6
+ padding: 0
+ onClicked: control.stepHeight(true)
+
+ background: Rectangle {
+ color: parent.hovered ? "#e0e0e0" : "transparent"
+ border.color: "#cccccc"
+ border.width: 1
+ radius: 2
+ }
+ }
+
+ Button {
+ width: 12
+ height: 11
+ text: "▼"
+ font.pixelSize: 6
+ padding: 0
+ onClicked: control.stepHeight(false)
+
+ background: Rectangle {
+ color: parent.hovered ? "#e0e0e0" : "transparent"
+ border.color: "#cccccc"
+ border.width: 1
+ radius: 2
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+ }
+
+ // 当value从外部改变时,更新输入框显示
+ onValueChanged: {
+ if (value) {
+ if (!widthBox.activeFocus) {
+ widthBox.text = value.width.toFixed(decimals)
+ }
+ if (!heightBox.activeFocus) {
+ heightBox.text = value.height.toFixed(decimals)
+ }
+
+ // 发出单独的宽高变化信号
+ sizeWidthChanged(value.width)
+ sizeHeightChanged(value.height)
+ }
+ }
+}
diff --git a/PropertyEditor/source/src/QQuickDetailsViewBasicTypeEditor.cpp b/PropertyEditor/source/src/QQuickDetailsViewBasicTypeEditor.cpp
index 4933e8a..727f6d2 100644
--- a/PropertyEditor/source/src/QQuickDetailsViewBasicTypeEditor.cpp
+++ b/PropertyEditor/source/src/QQuickDetailsViewBasicTypeEditor.cpp
@@ -162,6 +162,188 @@ void QQuickDetailsViewManager::RegisterBasicTypeEditor() {
return valueEditor;
});
+ registerTypeEditor(QMetaType::fromType(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
+ QQmlEngine* engine = qmlEngine(parent);
+ QQmlContext* context = qmlContext(parent);
+ QQmlComponent comp(engine);
+ comp.setData(R"(
+ import QtQuick;
+ import QtQuick.Controls;
+ import "qrc:/resources/Qml/ValueEditor"
+ BoolBox{
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width
+ }
+ )", QUrl());
+ QVariantMap initialProperties;
+ initialProperties["parent"] = QVariant::fromValue(parent);
+ auto valueEditor = qobject_cast(comp.createWithInitialProperties(initialProperties, context));
+ if (!comp.errors().isEmpty()) {
+ qDebug() << comp.errorString();
+ }
+ valueEditor->setParentItem(parent);
+ valueEditor->setProperty("value", handle->getVar());
+ connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
+ connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
+ return valueEditor;
+ });
+
+ registerTypeEditor(QMetaType::fromType(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
+ QQmlEngine* engine = qmlEngine(parent);
+ QQmlContext* context = qmlContext(parent);
+ QQmlComponent comp(engine);
+ comp.setData(R"(
+ import QtQuick;
+ import QtQuick.Controls;
+ import "qrc:/resources/Qml/ValueEditor"
+ PointFBox{
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width
+ }
+ )", QUrl());
+ QVariantMap initialProperties;
+ initialProperties["parent"] = QVariant::fromValue(parent);
+ auto valueEditor = qobject_cast(comp.createWithInitialProperties(initialProperties, context));
+ if (!comp.errors().isEmpty()) {
+ qDebug() << comp.errorString();
+ }
+ valueEditor->setParentItem(parent);
+ valueEditor->setProperty("value", handle->getVar());
+ connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
+ connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
+ return valueEditor;
+ });
+
+ registerTypeEditor(QMetaType::fromType(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
+ QQmlEngine* engine = qmlEngine(parent);
+ QQmlContext* context = qmlContext(parent);
+ QQmlComponent comp(engine);
+ comp.setData(R"(
+ import QtQuick;
+ import QtQuick.Controls;
+ import "qrc:/resources/Qml/ValueEditor"
+ PointFBox{
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width
+ }
+ )", QUrl());
+ QVariantMap initialProperties;
+ initialProperties["parent"] = QVariant::fromValue(parent);
+ auto valueEditor = qobject_cast(comp.createWithInitialProperties(initialProperties, context));
+ if (!comp.errors().isEmpty()) {
+ qDebug() << comp.errorString();
+ }
+ valueEditor->setParentItem(parent);
+ valueEditor->setProperty("value", handle->getVar());
+ connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
+ connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
+ return valueEditor;
+ });
+
+ registerTypeEditor(QMetaType::fromType(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
+ QQmlEngine* engine = qmlEngine(parent);
+ QQmlContext* context = qmlContext(parent);
+ QQmlComponent comp(engine);
+ comp.setData(R"(
+ import QtQuick;
+ import QtQuick.Controls;
+ import "qrc:/resources/Qml/ValueEditor"
+ RectFBox{
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width
+ }
+ )", QUrl());
+ QVariantMap initialProperties;
+ initialProperties["parent"] = QVariant::fromValue(parent);
+ auto valueEditor = qobject_cast(comp.createWithInitialProperties(initialProperties, context));
+ if (!comp.errors().isEmpty()) {
+ qDebug() << comp.errorString();
+ }
+ valueEditor->setParentItem(parent);
+ valueEditor->setProperty("value", handle->getVar());
+ connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
+ connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
+ return valueEditor;
+ });
+
+ registerTypeEditor(QMetaType::fromType(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
+ QQmlEngine* engine = qmlEngine(parent);
+ QQmlContext* context = qmlContext(parent);
+ QQmlComponent comp(engine);
+ comp.setData(R"(
+ import QtQuick;
+ import QtQuick.Controls;
+ import "qrc:/resources/Qml/ValueEditor"
+ RectFBox{
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width
+ }
+ )", QUrl());
+ QVariantMap initialProperties;
+ initialProperties["parent"] = QVariant::fromValue(parent);
+ auto valueEditor = qobject_cast(comp.createWithInitialProperties(initialProperties, context));
+ if (!comp.errors().isEmpty()) {
+ qDebug() << comp.errorString();
+ }
+ valueEditor->setParentItem(parent);
+ valueEditor->setProperty("value", handle->getVar());
+ connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
+ connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
+ return valueEditor;
+ });
+
+ registerTypeEditor(QMetaType::fromType(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
+ QQmlEngine* engine = qmlEngine(parent);
+ QQmlContext* context = qmlContext(parent);
+ QQmlComponent comp(engine);
+ comp.setData(R"(
+ import QtQuick;
+ import QtQuick.Controls;
+ import "qrc:/resources/Qml/ValueEditor"
+ SizeFBox{
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width
+ }
+ )", QUrl());
+ QVariantMap initialProperties;
+ initialProperties["parent"] = QVariant::fromValue(parent);
+ auto valueEditor = qobject_cast(comp.createWithInitialProperties(initialProperties, context));
+ if (!comp.errors().isEmpty()) {
+ qDebug() << comp.errorString();
+ }
+ valueEditor->setParentItem(parent);
+ valueEditor->setProperty("value", handle->getVar());
+ connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
+ connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
+ return valueEditor;
+ });
+
+ registerTypeEditor(QMetaType::fromType(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
+ QQmlEngine* engine = qmlEngine(parent);
+ QQmlContext* context = qmlContext(parent);
+ QQmlComponent comp(engine);
+ comp.setData(R"(
+ import QtQuick;
+ import QtQuick.Controls;
+ import "qrc:/resources/Qml/ValueEditor"
+ SizeFBox{
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width
+ }
+ )", QUrl());
+ QVariantMap initialProperties;
+ initialProperties["parent"] = QVariant::fromValue(parent);
+ auto valueEditor = qobject_cast(comp.createWithInitialProperties(initialProperties, context));
+ if (!comp.errors().isEmpty()) {
+ qDebug() << comp.errorString();
+ }
+ valueEditor->setParentItem(parent);
+ valueEditor->setProperty("value", handle->getVar());
+ connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
+ connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
+ return valueEditor;
+ });
+
registerTypeEditor(QMetaType::fromType(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
QQmlEngine* engine = qmlEngine(parent);
QQmlContext* context = qmlContext(parent);