import QtQuick 2.12
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtCharts 2.15
import QtQuick.Window 2.12
ApplicationWindow {
visible: true
width: 1024
height: 768
title: qsTr("MainStream EtCO2 Monitor")
property var dataPoints: []
property var dataSeries: []
property int maxPoints: 400
property int currentIndex: 0
property int maxSeries: 2
property bool replacing: false
Rectangle {
id: root
anchors.fill: parent
color: "black"
Rectangle {
id: header
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: parent.height * 0.15
color: "black"
Rectangle {
id: titleRect
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: header.height * 0.5
color: "black"
Text {
id: titleLabel
text: qsTr("MainStream EtCO2 Monitor")
color: "#ffff00"
anchors.centerIn: parent
font.pixelSize: 32
font.family: "Arial"
font.bold: true
}
}
Rectangle {
id: subHeaderRow
anchors {
top: titleRect.bottom
left: parent.left
right: parent.right
}
height: header.height * 0.5
color: "black"
Rectangle {
id: versionRect
anchors {
top: parent.top
left: parent.left
bottom: parent.bottom
}
width: parent.width * 0.5
color: "black"
Text {
id: versionLabel
text: "Version: 1 Test OK!"
color: "orange"
anchors.centerIn: parent
font.pixelSize: 14
font.family: "Arial"
}
}
Rectangle {
id: dateTimeRect
anchors {
top: parent.top
right: parent.right
bottom: parent.bottom
}
width: parent.width * 0.5
color: "black"
Label {
id: dateTimeLabel
text: "2024-07-09 09:41:28"
color: "orange"
anchors.centerIn: parent
font.pixelSize: 14
font.family: "Arial"
}
}
}
}
Rectangle {
id: mainContent
anchors {
top: header.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
color: "black"
Rectangle {
id: left
anchors {
top: parent.top
left: parent.left
bottom: parent.bottom
}
width: parent.width * 0.3
color: "black"
// EtCO2 / FiCO2
Rectangle {
id: etco2Rect
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: parent.height * 0.30
color: "black"
Rectangle {
id: etco2Column
anchors.fill: parent
color: "black"
Text {
id: etco2Label
text: "EtCO2 / FiCO2"
color: "#00ff95"
font.pixelSize: 18
font.family: "Arial"
anchors{
left: parent.left
leftMargin: 10
top: parent.top
topMargin: 10
}
}
Text {
id: etco2Value
text: "--"
color: "#00ff95"
font.pixelSize: 48
font.family: "Arial"
font.bold: true
anchors{
right: separadorCO2.left
top: etco2Label.bottom
topMargin: 20
}
}
Text {
id: separadorCO2
text: " / "
color: "#00ff95"
font.pixelSize: 48
font.family: "Arial"
font.bold: true
anchors{
horizontalCenter: parent.horizontalCenter
top: etco2Label.bottom
topMargin: 20
}
}
Text {
id: fiCO2Value
text: "--"
color: "#00ff95"
font.pixelSize: 48
font.family: "Arial"
font.bold: true
anchors{
left: separadorCO2.right
top: etco2Label.bottom
topMargin: 20
}
}
Text {
id: etco2Unit
text: "mmHg"
color: "#00ff95"
font.pixelSize: 18
font.family: "Arial"
anchors{
right: parent.right
rightMargin: 30
top: etco2Value.bottom
topMargin: 20
}
}
border.color: "white"
}
}
// AwRR
Rectangle {
id: awrrRect
anchors {
top: etco2Rect.bottom
left: parent.left
right: parent.right
}
height: parent.height * 0.30
color: "black"
Rectangle {
id: awrrColumn
anchors.fill: parent
color: "black"
Text {
id: awrrLabel
text: "AwRR"
color: "#e11508"
font.pixelSize: 18
font.family: "Arial"
anchors{
left: parent.left
leftMargin: 20
top: parent.top
topMargin: 10
}
}
Text {
id: awrrValue
text: "0"
color: "#e11508"
font.pixelSize: 48
font.family: "Arial"
font.bold: true
anchors{
horizontalCenter: parent.horizontalCenter
top: awrrLabel.bottom
topMargin: 20
}
}
Text {
id: awrrUnit
text: "rpm"
color: "#e11508"
font.pixelSize: 18
font.family: "Arial"
anchors{
right: parent.right
rightMargin: 30
top: awrrValue.bottom
topMargin: 20
}
}
border.color: "white"
}
}
// EtO2 / FiO2
Rectangle {
id: etO2Rect
anchors {
top: awrrRect.bottom
left: parent.left
right: parent.right
}
height: parent.height * 0.30
color: "black"
Rectangle {
id: etO2Column
anchors.fill: parent
color: "black"
Text {
id: etO2Label
text: "EtO2 / FiO2"
color: "#fdffff"
font.pixelSize: 18
font.family: "Arial"
anchors{
left: parent.left
leftMargin: 20
top: parent.top
topMargin: 10
}
}
Text {
id: etO2Value
text: "--"
color: "#fdffff"
font.pixelSize: 48
font.family: "Arial"
font.bold: true
anchors{
right: separadorO2.left
top: etO2Label.bottom
topMargin: 20
}
}
Text {
id: separadorO2
text: " / "
color: "#fdffff"
font.pixelSize: 48
font.family: "Arial"
font.bold: true
anchors{
horizontalCenter: parent.horizontalCenter
top: etO2Label.bottom
topMargin: 20
}
}
Text {
id: fiO2Value
text: "--"
color: "#fdffff"
font.pixelSize: 48
font.family: "Arial"
font.bold: true
anchors{
left: separadorO2.right
top: etO2Label.bottom
topMargin: 20
}
}
Text {
id: etO2Unit
text: "%"
color: "#fdffff"
font.pixelSize: 18
font.family: "Arial"
anchors{
right: parent.right
rightMargin: 30
top: etO2Value.bottom
topMargin: 20
}
}
border.color: "white"
}
}
Rectangle {
id: statusRect
anchors {
top: etO2Rect.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
bottomMargin: 10
}
color: "black"
Text {
id: statusLabel
text: "apnea"
color: "#c200ac"
font.pixelSize: 20
font.family: "Arial"
anchors{
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 15
}
}
border.color: "white"
}
}
Rectangle {
id: right
anchors {
top: parent.top
right: parent.right
rightMargin: 10
bottom: parent.bottom
bottomMargin: 10
}
width: parent.width * 0.7
color: "black"
Rectangle {
id: graph1
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: parent.height * 0.5
color: "black"
border.color: "white"
Text {
id: graph1Title
text: "Capnography / mmHg"
color: "#00ff95"
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
topMargin: 10
}
font.pixelSize: 20
font.family: "Arial"
}
Text {
id: realTimeData
text: "--"
color: "#00ff95"
anchors {
top: parent.top
topMargin: 10
right: realTimeDataUnits.left
rightMargin: 5
}
font.pixelSize: 15
font.family: "Arial"
}
Text {
id: realTimeDataUnits
text: " mmHg"
color: "#00ff95"
anchors {
top: parent.top
topMargin: 10
right: parent.right
rightMargin: 10
}
font.pixelSize: 15
font.family: "Arial"
}
Row {
anchors {
top: graph1Title.bottom
left: parent.left
leftMargin: 10
bottom: parent.bottom
bottomMargin: 10
}
spacing: 10
Column {
spacing: 11
Repeater {
model: 11
Text {
text: 100 - index * 10
color: "#ffff00"
font.pixelSize: 14
font.family: "Arial"
}
}
}
Column {
spacing: (parent.height) / 60
Repeater {
model: 51
Rectangle {
width: index % 5 == 0 ? 15 : 10
height: 1
color: "#ffff00"
}
}
}
}
Canvas {
id: canvas
anchors.fill: parent
onPaint: {
var ctx = getContext("2d");
ctx.clearRect(0, 0, width, height);
ctx.strokeStyle = "blue";
ctx.lineWidth = 2;
ctx.beginPath();
var scaleX = width / maxPoints;
var scaleY = height / 100;
if (dataPoints.length > 0) {
for (var i = 0; i < dataPoints.length; i++) {
var x = 62 + (i % maxPoints) * scaleX;
var y = height - 5 - dataPoints[i] * scaleY;
if (i === 0 || (i === currentIndex && replacing)) {
ctx.moveTo(x, y);
} else if ((i === currentIndex - 1 && replacing) || (i === (currentIndex - 2 + maxPoints) % maxPoints && replacing)){
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
}
}
ctx.stroke();
}
}
Connections {
target: capnograph
function onYValueChanged(newValueY) {
realTimeData.text = newValueY;
replacing = dataPoints.length >= maxPoints;
if (replacing) {
dataPoints[currentIndex] = newValueY;
} else {
dataPoints.push(newValueY);
}
// Incrementar el índice actual y reiniciarlo si alcanza el límite
currentIndex = (currentIndex + 1) % maxPoints;
canvas.requestPaint();
}
}
}
Rectangle {
id: graph2
anchors {
top: graph1.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
color: "black"
border.color: "white"
Text {
id: graph2Title
text: "O2 / %"
color: "#00ff95"
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
topMargin: 10
}
font.pixelSize: 20
font.family: "Arial"
}
Row {
anchors {
top: graph2Title.bottom
left: parent.left
leftMargin: 10
bottom: parent.bottom
bottomMargin: 10
}
spacing: 10
Column {
spacing: 12
Repeater {
model: 11
Text {
text: 100 - index * 10
color: "#ffff00"
font.pixelSize: 14
font.family: "Arial"
}
}
}
Column {
spacing: (parent.height) / 60
Repeater {
model: 51
Rectangle {
width: index % 5 == 0 ? 15 : 10
height: 1
color: "#ffff00"
}
}
}
}
}
}
}
}
Connections {
target: capnograph
function onDataPacket84(etco2, insco2, awrr, eto2, inso2) {
etco2Value.text = etco2
fiCO2Value.text = insco2
awrrValue.text = awrr
etO2Value.text = eto2
fiO2Value.text = inso2
}
}
Timer {
interval: 1000;
running: true;
repeat: true
onTriggered: {
var date = new Date();
var hours = date.getHours().toString().padStart(2, '0');
var minutes = date.getMinutes().toString().padStart(2, '0');
var seconds = date.getSeconds().toString().padStart(2, '0');
var day = date.getDate().toString().padStart(2, '0');
var month = (date.getMonth() + 1).toString().padStart(2, '0');
var year = date.getFullYear();
dateTimeLabel.text = year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds;
}
}
}
/*
Ir guardando los puntos en un arreglo y se quedan estaticos hasta que su valor en x vuelva a ser 0
Y no se borran
Connections {
target: capnograph
function onXValueChanged(newValueX) {
// console.log("New data received X: ", newValueX);
//dataPoints.push({ xValue: capnograph.xValue, yValue: capnograph.yValue });
//console.log(dataPoints)
//if (newValueX === 100) {
// scaleX = 0;
// points.shift(); // Mantener solo los últimos 100 puntos
//}
canvas.requestPaint();
}
}
Connections {
target: capnograph
function onYValueChanged(newValueY) {
//console.log("New data received Y: ", newValueY);
realTimeData.text = newValueY
dataPoints.push(newValueY);
if (dataPoints.length == 300) {
//dataPoints.shift(); // Mantener solo los últimos 100 puntos
//dataPoints = []
//scaleX = 0
// de este código es necesario identificar el primer punto en el eje x en el que se grafica y el último del límite
// cuando llegue al valor límite empieza a graficar desde el inicio.
for (var i = 0; i < dataPoints.length; i++) {
dataPoints[i] = newValueY
}
}
canvas.requestPaint();
}
}
*/