diff --git a/graphics/Buzzer.xcf b/graphics/Buzzer.xcf index 840ecfb..2cac802 100644 Binary files a/graphics/Buzzer.xcf and b/graphics/Buzzer.xcf differ diff --git a/graphics/speedclimbing_stopwatch.xcf b/graphics/speedclimbing_stopwatch.xcf index f92c268..1ea0472 100644 Binary files a/graphics/speedclimbing_stopwatch.xcf and b/graphics/speedclimbing_stopwatch.xcf differ diff --git a/headers/climbingrace.h b/headers/climbingrace.h index b0c9469..5382646 100644 --- a/headers/climbingrace.h +++ b/headers/climbingrace.h @@ -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(); diff --git a/headers/speedtimer.h b/headers/speedtimer.h index 6d919e9..a4061da 100644 --- a/headers/speedtimer.h +++ b/headers/speedtimer.h @@ -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 diff --git a/qml/main.qml b/qml/main.qml index 17a9362..0fd6436 100644 --- a/qml/main.qml +++ b/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 - elide: "ElideRight" + + opacity: ( speedBackend.state < 3 ) ? 1:0 + + width: parent.width * 0.8 + + text: "" + color: appTheme.style.textColor - font.pixelSize: 100 + fontSizeMode: Text.Fit - text: speedBackend.timers[0]["text"] + 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 + FadeAnimation{ + target: topLa } } } - 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 - anchors { - horizontalCenter: parent.horizontalCenter - top: timer_1.bottom - topMargin: parent.height * 0.1 + 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 + + text: speedBackend.timers[index]["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: timerTextLa + } + } + } + + Label { + id: react_time + + property int rtime: speedBackend.timers[index]["reacttime"] + + anchors { + 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 } diff --git a/sources/climbingrace.cpp b/sources/climbingrace.cpp index cdd24b5..50922c1 100644 --- a/sources/climbingrace.cpp +++ b/sources/climbingrace.cpp @@ -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 --- // ------------------------- diff --git a/sources/speedtimer.cpp b/sources/speedtimer.cpp index 5350e8a..8265870 100644 --- a/sources/speedtimer.cpp +++ b/sources/speedtimer.cpp @@ -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;