417 lines
17 KiB
QML
417 lines
17 KiB
QML
import QtQuick 2.15
|
|
import QtQuick.Controls 2.15
|
|
import QtQuick.Layouts 1.15
|
|
import AntiClipSettings 1.0
|
|
|
|
Item {
|
|
id: root
|
|
property alias enabled: shieldedRow.enabled
|
|
property int dargWidth: 12
|
|
property color openDoorAreaColor: "#0FF40D" // 绿色
|
|
property var openDoorAreaPoints: []
|
|
property int openDoorAreaWay: 0
|
|
property color shieldedAreaColor: "yellow"
|
|
property var shieldedAreaPoints: []
|
|
property bool shieldedAreaEnabled: false
|
|
property color antiClipAreaColor: "blue"
|
|
property var antiClipAreaPoints: []
|
|
property bool antiClipAreaEnabled: false
|
|
property int antiClipSensitivity: 1
|
|
property alias flip: flipSwitch.checked
|
|
property alias videoRotation: rotateComboBox.currentIndex
|
|
|
|
Item {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
anchors.bottom: controlBar.top
|
|
Image {
|
|
id: image
|
|
anchors.centerIn: parent
|
|
cache: false
|
|
fillMode: Image.PreserveAspectFit
|
|
source: "image://videoframe/"
|
|
property real aspectRatio: 16 / 9
|
|
width: Math.min(parent.width, parent.height * aspectRatio)
|
|
height: width / aspectRatio
|
|
enabled: root.enabled
|
|
|
|
Canvas {
|
|
id: canvas
|
|
anchors.fill: parent
|
|
onPaint: {
|
|
|
|
var ctx = canvas.getContext("2d")
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
|
if(!root.enabled)return
|
|
if(openDoorAreaWay == DeviceConnection.FullArea){
|
|
ctx.strokeStyle = openDoorAreaColor
|
|
ctx.lineWidth = 8
|
|
ctx.strokeRect(0,0, canvas.width,
|
|
canvas.height)
|
|
|
|
} else if ((openDoorAreaWay>=DeviceConnection.Quadrangle) &&(openDoorAreaPoints.length > 0)) {
|
|
ctx.strokeStyle = openDoorAreaColor
|
|
ctx.lineWidth = 2
|
|
|
|
ctx.beginPath()
|
|
let point = scaledPoint(openDoorAreaPoints[0],
|
|
width, height)
|
|
ctx.moveTo(point.x, point.y)
|
|
for (var i = 1; i < openDoorAreaPoints.length; i++) {
|
|
point = scaledPoint(openDoorAreaPoints[i],
|
|
width, height)
|
|
ctx.lineTo(point.x, point.y)
|
|
}
|
|
ctx.closePath()
|
|
ctx.stroke()
|
|
}
|
|
if (antiClipAreaEnabled && (antiClipAreaPoints.length > 0)) {
|
|
ctx.strokeStyle = antiClipAreaColor
|
|
ctx.lineWidth = 2
|
|
|
|
ctx.beginPath()
|
|
let point = scaledPoint(antiClipAreaPoints[0],
|
|
width, height)
|
|
ctx.moveTo(point.x, point.y)
|
|
for (var i = 1; i < antiClipAreaPoints.length; i++) {
|
|
point = scaledPoint(antiClipAreaPoints[i],
|
|
width, height)
|
|
ctx.lineTo(point.x, point.y)
|
|
}
|
|
ctx.closePath()
|
|
ctx.stroke()
|
|
}
|
|
if (shieldedAreaEnabled &&(shieldedAreaPoints.length > 0)) {
|
|
ctx.lineWidth = 2
|
|
ctx.strokeStyle = shieldedAreaColor
|
|
let point0 = scaledPoint(shieldedAreaPoints[0],
|
|
width, height)
|
|
let point1 = scaledPoint(shieldedAreaPoints[1],
|
|
width, height)
|
|
let point2 = scaledPoint(shieldedAreaPoints[2],
|
|
width, height)
|
|
let point3 = scaledPoint(shieldedAreaPoints[3],
|
|
width, height)
|
|
ctx.strokeRect(point0.x, point0.y, point1.x - point0.x,
|
|
point1.y - point0.y)
|
|
ctx.strokeRect(point2.x, point2.y, point3.x - point2.x,
|
|
point3.y - point2.y)
|
|
}
|
|
}
|
|
}
|
|
|
|
Repeater {
|
|
id: repeater
|
|
visible: openDoorAreaWay>=DeviceConnection.Quadrangle
|
|
model: openDoorAreaPoints
|
|
delegate: Rectangle {
|
|
width: dargWidth
|
|
height: dargWidth
|
|
visible: root.enabled &&(openDoorAreaWay>=DeviceConnection.Quadrangle)
|
|
color: openDoorAreaColor
|
|
x: scaledPoint(modelData, canvas.width,
|
|
canvas.height).x - width / 2
|
|
y: scaledPoint(modelData, canvas.width,
|
|
canvas.height).y - height / 2
|
|
}
|
|
}
|
|
|
|
Repeater {
|
|
id: shieldedAreaRepeater
|
|
model: shieldedAreaPoints
|
|
visible: shieldedAreaEnabled
|
|
delegate: Rectangle {
|
|
width: dargWidth
|
|
height: dargWidth
|
|
visible: root.enabled && shieldedAreaEnabled
|
|
color: shieldedAreaColor
|
|
x: scaledPoint(modelData, canvas.width,
|
|
canvas.height).x - width / 2
|
|
y: scaledPoint(modelData, canvas.width,
|
|
canvas.height).y - height / 2
|
|
}
|
|
}
|
|
|
|
Repeater {
|
|
id: antiAreaRepeater
|
|
visible: antiClipAreaEnabled
|
|
model: antiClipAreaPoints
|
|
delegate: Rectangle {
|
|
visible: root.enabled && antiClipAreaEnabled
|
|
width: dargWidth
|
|
height: dargWidth
|
|
color: antiClipAreaColor
|
|
x: scaledPoint(modelData, canvas.width,
|
|
canvas.height).x - width / 2
|
|
y: scaledPoint(modelData, canvas.width,
|
|
canvas.height).y - height / 2
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
enabled: root.enabled
|
|
property int draggedOpenDoorAreaPointIndex: -1
|
|
property int draggedShieldedAreaPointIndex: -1
|
|
property int draggedAntiAreaPointIndex: -1
|
|
onPressed: mouse => {
|
|
if(openDoorAreaWay == DeviceConnection.Quadrangle){
|
|
for (var i = 0; i < openDoorAreaPoints.length; i++) {
|
|
let point = scaledPoint(
|
|
openDoorAreaPoints[i], canvas.width,
|
|
canvas.height)
|
|
if (isInside(mouse.x, mouse.y, point)) {
|
|
draggedOpenDoorAreaPointIndex = i
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if (draggedOpenDoorAreaPointIndex >= 0)
|
|
return
|
|
if(shieldedAreaEnabled){
|
|
for (let i = 0; i < shieldedAreaPoints.length; i++) {
|
|
let point = scaledPoint(
|
|
shieldedAreaPoints[i], canvas.width,
|
|
canvas.height)
|
|
if (isInside(mouse.x, mouse.y, point)) {
|
|
draggedShieldedAreaPointIndex = i
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if (draggedShieldedAreaPointIndex >= 0)
|
|
return
|
|
if(antiClipAreaEnabled){
|
|
for (let i = 0; i < antiClipAreaPoints.length; i++) {
|
|
let point = scaledPoint(
|
|
antiClipAreaPoints[i], canvas.width,
|
|
canvas.height)
|
|
if (isInside(mouse.x, mouse.y, point)) {
|
|
draggedAntiAreaPointIndex = i
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
onReleased: {
|
|
if (draggedOpenDoorAreaPointIndex >= 0) {
|
|
App.updateOpenDoorAreaPoints(openDoorAreaPoints)
|
|
draggedOpenDoorAreaPointIndex = -1
|
|
}
|
|
if (draggedShieldedAreaPointIndex >= 0) {
|
|
App.updateShieldedAreaPoints(shieldedAreaPoints)
|
|
draggedShieldedAreaPointIndex = -1
|
|
}
|
|
if (draggedAntiAreaPointIndex >= 0) {
|
|
App.updateAntiClipAreaPoints(antiClipAreaPoints)
|
|
draggedAntiAreaPointIndex = -1
|
|
}
|
|
}
|
|
onPositionChanged: mouse => {
|
|
if ((mouse.x < 0) || (mouse.x > canvas.width) || (mouse.y < 0) || (mouse.y > canvas.height)) return
|
|
if (draggedOpenDoorAreaPointIndex >= 0) {
|
|
openDoorAreaPoints[draggedOpenDoorAreaPointIndex]
|
|
= standardPoint(Qt.point(mouse.x, mouse.y), canvas.width, canvas.height)
|
|
canvas.requestPaint()
|
|
repeater.model = openDoorAreaPoints
|
|
} else if (draggedShieldedAreaPointIndex >= 0) {
|
|
shieldedAreaPoints[draggedShieldedAreaPointIndex]
|
|
= standardPoint(Qt.point(mouse.x,
|
|
mouse.y),
|
|
canvas.width,
|
|
canvas.height)
|
|
canvas.requestPaint()
|
|
shieldedAreaRepeater.model = shieldedAreaPoints
|
|
} else if (draggedAntiAreaPointIndex >= 0) {
|
|
antiClipAreaPoints[draggedAntiAreaPointIndex]
|
|
= standardPoint(Qt.point(mouse.x,
|
|
mouse.y),
|
|
canvas.width,
|
|
canvas.height)
|
|
canvas.requestPaint()
|
|
antiAreaRepeater.model = antiClipAreaPoints
|
|
}
|
|
}
|
|
|
|
function isInside(x, y, point) {
|
|
let edge = dargWidth / 2
|
|
return x >= point.x - edge && x <= point.x + edge
|
|
&& y >= point.y - edge && y <= point.y + edge
|
|
}
|
|
}
|
|
}
|
|
}
|
|
GridLayout {
|
|
id: controlBar
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: parent.bottom
|
|
columns: 4
|
|
|
|
Label { text: qsTr("图像: ") }
|
|
|
|
Row {
|
|
enabled: root.enabled
|
|
Layout.columnSpan: 3
|
|
Label {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: qsTr("旋转")
|
|
}
|
|
Item {width: 10; height:10}
|
|
ComboBox {
|
|
id: rotateComboBox
|
|
model: ["0°","90°","180°","270°"]
|
|
onCurrentIndexChanged: {
|
|
App.currentDeviceRotation = rotateComboBox.currentIndex
|
|
}
|
|
}
|
|
Item {width: 70; height:10}
|
|
Label {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: qsTr("翻转")
|
|
}
|
|
Item {width: 10; height:10}
|
|
Switch {
|
|
id: flipSwitch
|
|
onToggled: App.currentDeviceFlip=flipSwitch.checked
|
|
}
|
|
}
|
|
|
|
Label {
|
|
text: qsTr("开门区域: ")
|
|
}
|
|
Row {
|
|
enabled: root.enabled
|
|
Layout.columnSpan: 3
|
|
RadioButton {
|
|
text: "关闭"
|
|
checked: App.currentOpenDoorAreaWay ==DeviceConnection.Diabled
|
|
onToggled:{
|
|
App.currentOpenDoorAreaWay =DeviceConnection.Diabled
|
|
}
|
|
}
|
|
RadioButton {
|
|
text: "全区域"
|
|
checked: App.currentOpenDoorAreaWay ==DeviceConnection.FullArea
|
|
onToggled:{
|
|
App.currentOpenDoorAreaWay =DeviceConnection.FullArea
|
|
}
|
|
}
|
|
RadioButton {
|
|
text: "四边形"
|
|
checked: App.currentOpenDoorAreaWay ==DeviceConnection.Quadrangle
|
|
onToggled:{
|
|
App.currentOpenDoorAreaWay =DeviceConnection.Quadrangle
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Label {text: qsTr("防夹区域: ")}
|
|
Row {
|
|
enabled: root.enabled
|
|
Layout.columnSpan: 1
|
|
RadioButton {
|
|
text: "关闭"
|
|
checked: !App.currentAntiClipAreaEnabled
|
|
onToggled: {
|
|
App.currentAntiClipAreaEnabled=false
|
|
}
|
|
|
|
}
|
|
RadioButton {
|
|
text: "四边形"
|
|
checked: App.currentAntiClipAreaEnabled
|
|
onToggled: {
|
|
App.currentAntiClipAreaEnabled=true
|
|
}
|
|
}
|
|
|
|
}
|
|
Label { text: qsTr("灵敏度: ")
|
|
Layout.alignment: Qt.AlignRight
|
|
}
|
|
ComboBox {
|
|
id: antiClipSensitivityComboBox
|
|
enabled: root.enabled
|
|
Layout.alignment: Qt.AlignLeft
|
|
model: [1,2,3,4,5]
|
|
currentIndex: root.antiClipSensitivity-1
|
|
onCurrentIndexChanged: {
|
|
App.currentAntiClipSensitivity = antiClipSensitivityComboBox.currentIndex+1
|
|
}
|
|
}
|
|
|
|
Label {text: qsTr("屏蔽区域: ")}
|
|
Row {
|
|
id: shieldedRow
|
|
RadioButton {
|
|
checked: !shieldedAreaEnabled
|
|
text: "关闭"
|
|
onToggled: {
|
|
App.currentShieldedAreaEnabled = false
|
|
}
|
|
}
|
|
RadioButton {
|
|
checked: shieldedAreaEnabled
|
|
text: "开启"
|
|
onToggled: {
|
|
App.currentShieldedAreaEnabled = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// 转换为显示画点
|
|
function scaledPoint(point, width, height) {
|
|
let x = point.x * width / App.DeviceWidth
|
|
let y = point.y * height / App.DeviceHeight
|
|
return Qt.point(x, y)
|
|
}
|
|
|
|
// 转换为设备画点(640x360)
|
|
function standardPoint(point, width, height) {
|
|
let x = point.x * App.DeviceWidth / width
|
|
let y = point.y * App.DeviceHeight / height
|
|
return Qt.point(x, y)
|
|
}
|
|
|
|
onEnabledChanged: {
|
|
canvas.requestPaint()
|
|
if(!enabled){
|
|
image.source = "image://videoframe/black"
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: App
|
|
function onNewVideoFrame() {
|
|
image.source = ""
|
|
image.source = "image://videoframe/"
|
|
}
|
|
function onCurrentOpenDoorAreaPointsChanged() {
|
|
canvas.requestPaint()
|
|
repeater.model = openDoorAreaPoints
|
|
}
|
|
function onCurrentShieldedAreaPointsChanged() {
|
|
shieldedAreaRepeater.model = shieldedAreaPoints
|
|
canvas.requestPaint()
|
|
}
|
|
function onCurrentAntiClipAreaPointsChanged() {
|
|
antiAreaRepeater.model = antiClipAreaPoints
|
|
canvas.requestPaint()
|
|
}
|
|
function onCurrentOpenDoorAreaWayChanged(){
|
|
canvas.requestPaint()
|
|
}
|
|
function onCurrentShieldedAreaEnabledChanged(){
|
|
canvas.requestPaint()
|
|
}
|
|
function onCurrentAntiClipAreaEnabledChanged(){
|
|
canvas.requestPaint()
|
|
}
|
|
}
|
|
}
|