DiagramDesigner/PropertyEditor/resources/Qml/ValueEditor/BoolBox.qml

185 lines
5.1 KiB
QML
Raw Normal View History

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
}
}
}