- cleanup
- implemented new state ('WAITING') - multiple timers are now supported at the frontend
This commit is contained in:
parent
ecd141515f
commit
0957a913f8
7 changed files with 173 additions and 55 deletions
Binary file not shown.
Binary file not shown.
|
@ -23,7 +23,7 @@ class ClimbingRace : public QObject
|
|||
public:
|
||||
explicit ClimbingRace(QObject *parent = nullptr);
|
||||
|
||||
enum raceState { IDLE, STARTING, RUNNING, STOPPED };
|
||||
enum raceState { IDLE, STARTING, WAITING, RUNNING, STOPPED };
|
||||
raceState state;
|
||||
|
||||
enum raceMode { LOCAL, REMOTE };
|
||||
|
@ -63,6 +63,8 @@ private slots:
|
|||
void refreshMode();
|
||||
void refreshTimerText();
|
||||
|
||||
bool refreshRemoteTimers();
|
||||
|
||||
signals:
|
||||
void nextStartActionChanged(int nextStartAction);
|
||||
void nextStartActionDelayProgressChanged();
|
||||
|
|
|
@ -13,7 +13,7 @@ class SpeedTimer : public QObject
|
|||
public:
|
||||
explicit SpeedTimer(QObject *parent = nullptr);
|
||||
|
||||
enum timerState { IDLE, STARTING, RUNNING, STOPPED, FAILED, CANCELLED };
|
||||
enum timerState { IDLE, STARTING, WAITING, RUNNING, STOPPED, FAILED, CANCELLED };
|
||||
timerState state;
|
||||
|
||||
// variables for capturing the time
|
||||
|
|
165
qml/main.qml
165
qml/main.qml
|
@ -67,10 +67,14 @@ Window {
|
|||
settingsDialog.close()
|
||||
break;
|
||||
case 2:
|
||||
stateString = "RUNNING"
|
||||
stateString = "WAITING"
|
||||
settingsDialog.close()
|
||||
break;
|
||||
case 3:
|
||||
stateString = "RUNNING"
|
||||
settingsDialog.close()
|
||||
break;
|
||||
case 4:
|
||||
stateString = "STOPPED"
|
||||
settingsDialog.close()
|
||||
}
|
||||
|
@ -91,12 +95,13 @@ Window {
|
|||
spread: 0.02
|
||||
color: "black"
|
||||
opacity: 0.18
|
||||
anchors.fill: time_container
|
||||
anchors.fill: topContainerItm
|
||||
scale: 1
|
||||
}
|
||||
|
||||
Item {
|
||||
id: time_container
|
||||
id: topContainerItm
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
|
@ -117,34 +122,124 @@ Window {
|
|||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: timer_1
|
||||
Text {
|
||||
id: topLa
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
opacity: ( speedBackend.state < 3 ) ? 1:0
|
||||
|
||||
width: parent.width * 0.8
|
||||
|
||||
text: ""
|
||||
|
||||
color: appTheme.style.textColor
|
||||
|
||||
fontSizeMode: Text.Fit
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
font.pixelSize: root.landscape() ? parent.width * 0.15 : parent.height * 0.4
|
||||
|
||||
minimumPixelSize: 0
|
||||
|
||||
Behavior on text {
|
||||
FadeAnimation{
|
||||
target: topLa
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: timerCol
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
opacity: ( speedBackend.state < 3 ) ? 0:1
|
||||
|
||||
spacing: height * 0.05
|
||||
|
||||
Repeater {
|
||||
id: timerRep
|
||||
|
||||
model: speedBackend.timers.length
|
||||
|
||||
delegate: Item {
|
||||
id: timerDel
|
||||
|
||||
width: parent.width
|
||||
height: timerRep.model > 1 ? ( timerCol.height * 0.9 ) / timerRep.model:timerCol.height
|
||||
|
||||
Label {
|
||||
id: timerTextLa
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: ( parent.width * 0.8 )
|
||||
height: parent.height
|
||||
|
||||
elide: "ElideRight"
|
||||
color: appTheme.style.textColor
|
||||
|
||||
font.pixelSize: 100
|
||||
text: speedBackend.timers[index]["text"]
|
||||
|
||||
text: speedBackend.timers[0]["text"]
|
||||
fontSizeMode: Text.Fit
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
font.pixelSize: root.landscape() ? parent.width * 0.15 : parent.height * 0.4
|
||||
|
||||
minimumPixelSize: 0
|
||||
|
||||
Behavior on text {
|
||||
enabled: root.state !== "RUNNING"
|
||||
FadeAnimation {
|
||||
target: timer_1
|
||||
target: timerTextLa
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: react_time
|
||||
property int rtime: speedBackend.timers[0]["reacttime"]
|
||||
text: qsTr("reaction time (ms): ") + Math.round(rtime)
|
||||
opacity: (root.state === "RUNNING" || root.state === "STOPPED") && rtime !== 0 ? 1:0
|
||||
color: appTheme.style.textColor
|
||||
|
||||
property int rtime: speedBackend.timers[index]["reacttime"]
|
||||
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: timer_1.bottom
|
||||
topMargin: parent.height * 0.1
|
||||
centerIn: parent
|
||||
verticalCenterOffset: parent.height * 0.25
|
||||
}
|
||||
|
||||
width: ( parent.width * 0.6 )
|
||||
height: parent.height
|
||||
|
||||
fontSizeMode: Text.Fit
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
text: qsTr("reaction time (ms): ") + Math.round(rtime)
|
||||
|
||||
opacity: (root.state === "RUNNING" || root.state === "STOPPED") && rtime !== 0 ? 1:0
|
||||
|
||||
color: appTheme.style.textColor
|
||||
|
||||
font.pixelSize: timerTextLa.font.pixelSize * 0.5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -239,8 +334,8 @@ Window {
|
|||
width: root.landscape() ? 1:parent.width
|
||||
height: root.landscape() ? parent.height:1
|
||||
color: appTheme.style.lineColor
|
||||
anchors.left: root.landscape() ? time_container.right:parent.left
|
||||
anchors.top: root.landscape() ? parent.top:time_container.bottom
|
||||
anchors.left: root.landscape() ? topContainerItm.right:parent.left
|
||||
anchors.top: root.landscape() ? parent.top:topContainerItm.bottom
|
||||
anchors.bottom: root.landscape() ? parent.bottom:undefined
|
||||
visible: false
|
||||
}
|
||||
|
@ -524,9 +619,8 @@ Window {
|
|||
State {
|
||||
name: "IDLE"
|
||||
//state for the start page
|
||||
PropertyChanges { target: timer_1; font.pixelSize: root.landscape() ? parent.width * 0.1:parent.height * 0.3; scale: 1 }
|
||||
PropertyChanges {
|
||||
target: time_container;
|
||||
target: topContainerItm;
|
||||
anchors.bottomMargin: root.landscape() ? undefined:parent.height * 0.1;
|
||||
anchors.rightMargin: root.landscape() ? parent.height * 0.05:0
|
||||
}
|
||||
|
@ -537,8 +631,27 @@ Window {
|
|||
anchors.bottomMargin: parent.height * 0.5 - startButt.height * 0.5
|
||||
anchors.rightMargin: parent.width * 0.5 - startButt.width * 0.5
|
||||
}
|
||||
PropertyChanges {
|
||||
target: topLa
|
||||
text: qsTr("Click Start to start")
|
||||
}
|
||||
|
||||
},
|
||||
State {
|
||||
name: "WAITING"
|
||||
//state when a false start occured and waiting for time calculation
|
||||
PropertyChanges {
|
||||
target: startButt; enabled: false; text: qsTr("waiting...");
|
||||
anchors.rightMargin: root.landscape() ? parent.width * 0.05:parent.width * 0.5 - startButt.width * 0.5 //put the button more to the right to hide the menu (only in landscape mode)
|
||||
anchors.bottomMargin: root.landscape() ? parent.height * 0.5 - startButt.height * 0.5:parent.height * 0.1 //put the button lower to hide the menu (only in portrait mode)
|
||||
}
|
||||
PropertyChanges { target: cancelButt; scale: 0; enabled: false}
|
||||
PropertyChanges { target: menu_container; }
|
||||
PropertyChanges {
|
||||
target: topLa
|
||||
text: qsTr("please wait...")
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "STARTING"
|
||||
//state for the start sequence
|
||||
|
@ -546,14 +659,17 @@ Window {
|
|||
anchors.rightMargin: root.landscape() ? parent.width * 0.05:parent.width * 0.5 - startButt.width * 0.5 //put the button more to the right to hide the menu (only in landscape mode)
|
||||
anchors.bottomMargin: root.landscape() ? parent.height * 0.5 - startButt.height * 0.5:parent.height * 0.1 //put the button lower to hide the menu (only in portrait mode)
|
||||
}
|
||||
PropertyChanges { target: timer_1; font.pixelSize: root.landscape() ? parent.width * 0.2:parent.height * 0.3; scale: 1 }
|
||||
PropertyChanges { target: cancelButt; scale: 1}
|
||||
PropertyChanges { target: menu_container; }
|
||||
PropertyChanges {
|
||||
target: topLa
|
||||
text: qsTr("starting...")
|
||||
}
|
||||
|
||||
},
|
||||
State {
|
||||
name: "RUNNING"
|
||||
//state when the timer is running
|
||||
PropertyChanges { target: timer_1; font.pixelSize: root.landscape() ? parent.width * 0.2:parent.height * 0.3; scale: 1 }
|
||||
PropertyChanges { target: startButt; enabled: true;
|
||||
text: "stop"
|
||||
anchors.rightMargin: root.landscape() ? parent.width * 0.05:parent.width * 0.5 - startButt.width * 0.5 //put the button more to the right to hide the menu (only in landscape mode)
|
||||
|
@ -565,11 +681,6 @@ Window {
|
|||
State {
|
||||
name: "STOPPED"
|
||||
//state when the meassuring is over
|
||||
PropertyChanges {
|
||||
target: timer_1;
|
||||
font.pixelSize: root.landscape() ? parent.width * 0.15:parent.height * 0.1;
|
||||
scale: 1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: startButt;
|
||||
enabled: true; text: qsTr("reset");
|
||||
|
@ -578,7 +689,7 @@ Window {
|
|||
anchors.rightMargin: root.landscape() ? parent.height * 0.2 - startButt.height * 0.5:parent.width * 0.5 - startButt.width * 0.5
|
||||
}
|
||||
PropertyChanges {
|
||||
target: time_container;
|
||||
target: topContainerItm;
|
||||
anchors.rightMargin: root.landscape() ? 0-startButt.width/2:undefined
|
||||
anchors.bottomMargin: root.landscape() ? undefined:0-startButt.height/2
|
||||
}
|
||||
|
|
|
@ -226,9 +226,7 @@ void ClimbingRace::syncWithBaseStation() {
|
|||
case 1:
|
||||
{
|
||||
// case STARTING
|
||||
if(speedTimers[0]->state != 1){
|
||||
speedTimers[0]->setState(SpeedTimer::STARTING);
|
||||
}
|
||||
this->refreshRemoteTimers();
|
||||
|
||||
tmpReply = this->baseConn->sendCommand(2005);
|
||||
if(tmpReply["status"] != 200){
|
||||
|
@ -247,23 +245,7 @@ void ClimbingRace::syncWithBaseStation() {
|
|||
default:
|
||||
{
|
||||
|
||||
// get current time
|
||||
tmpReply = this->baseConn->sendCommand(2007);
|
||||
if(tmpReply["status"] != 200){
|
||||
//handle error!!
|
||||
qDebug() << "+ --- getting timers from basestation failed";
|
||||
this->baseStationSyncTimer->start();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
QVariantList timers = tmpReply["data"].toList();
|
||||
|
||||
speedTimers[0]->startTime = this->date->currentMSecsSinceEpoch() - timers[0].toMap()["currTime"].toDouble();
|
||||
speedTimers[0]->stoppedTime = timers[0].toMap()["currTime"].toDouble();
|
||||
speedTimers[0]->reactionTime = timers[0].toMap()["reactTime"].toDouble();
|
||||
|
||||
speedTimers[0]->setState(SpeedTimer::timerState(timers[0].toMap()["state"].toInt()));
|
||||
}
|
||||
this->refreshRemoteTimers();
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -443,6 +425,26 @@ void ClimbingRace::refreshTimerText() {
|
|||
this->timerTextRefreshTimer->start();
|
||||
}
|
||||
|
||||
bool ClimbingRace::refreshRemoteTimers() {
|
||||
// get current time
|
||||
QVariantMap tmpReply = this->baseConn->sendCommand(2007);
|
||||
if(tmpReply["status"] != 200){
|
||||
//handle error!!
|
||||
qDebug() << "+ --- getting timers from basestation failed";
|
||||
this->baseStationSyncTimer->start();
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
QVariantList timers = tmpReply["data"].toList();
|
||||
|
||||
speedTimers[0]->startTime = this->date->currentMSecsSinceEpoch() - timers[0].toMap()["currTime"].toDouble();
|
||||
speedTimers[0]->stoppedTime = timers[0].toMap()["currTime"].toDouble();
|
||||
speedTimers[0]->reactionTime = timers[0].toMap()["reactTime"].toDouble();
|
||||
|
||||
speedTimers[0]->setState(SpeedTimer::timerState(timers[0].toMap()["state"].toInt()));
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// --- functions for qml ---
|
||||
// -------------------------
|
||||
|
|
|
@ -132,6 +132,9 @@ QString SpeedTimer::getText() {
|
|||
case SpeedTimer::STARTING:
|
||||
newText = "0.000 sec";
|
||||
break;
|
||||
case SpeedTimer::WAITING:
|
||||
newText = tr("Please wait...");
|
||||
break;
|
||||
case SpeedTimer::RUNNING:
|
||||
newText = QString::number( this->getCurrTime() / 1000.0, 'f', 3 ) + " sec";
|
||||
break;
|
||||
|
|
Reference in a new issue