import QtQuick 2.9 import QtQuick.Window 2.2 import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 import Qt.labs.settings 1.0 import QtQuick.Layouts 1.0 import de.itsblue.ScStw 2.0 import de.itsblue.ScStwMonitor 2.0 Window { id: window visible: true width: XscreenWidth / 2 height: XscreenHeight / 2 title: qsTr("ScStwMonitor") //visibility: Window.FullScreen Page { id: app anchors.fill: parent function landscape() { return app.width > app.height } ScStwMonitorBackend { id: backend scStwClient.ipAddress: appSettings.baseStationIp } Settings { id: appSettings property string baseStationIp: "192.168.4.1" } Shortcut { sequences: ["Ctrl+Q", StandardKey.Back] onActivated: Qt.quit() } Shortcut { sequences: ["F11", "Esc"] onActivated: { if(window.visibility === Window.FullScreen) { window.visibility = Window.Windowed } else { window.visibility = Window.FullScreen } } } FontLoader { id: timerFont source:"qrc:///fonts/PTMono-Regular.ttf" } Loader { id: mainComponentLoader anchors.fill: parent sourceComponent: backend.scStwClient.state === ScStwClient.CONNECTED ? displayComp:loadingComp } Component { id: displayComp Item { id: displayItm anchors.fill: parent Image { id: bannerImg anchors { top: parent.top left: parent.left right: parent.right margins: app.landscape() ? app.height * 0.01:app.width * 0.1 } height: app.landscape() ? app.height * 0.25:app.height * 0.2 visible: showControls fillMode: Image.PreserveAspectFit mipmap: true source: "qrc:/Banner.png" } TimerColumn { anchors.fill: parent opacity: !showControls || [ScStwRace.IDLE,ScStwRace.STARTING].indexOf(backend.race.state) < 0 ? 1:0 Behavior on opacity { NumberAnimation { duration: 200 } } } Item { id: controlsItm anchors { left: parent.left right: parent.right bottom: parent.bottom } visible: showControls Label { id: clickHintLabel property string implicitText:[ "tap anywhere\nto start", "NEXT_START_ACTION", "please wait...", "running\ntap anywhere to stop", "tap anywhere to reset" ][backend.race.state] anchors.fill: parent verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter fontSizeMode: Text.Fit font.pixelSize: height * 0.3 color: backend.race.state === ScStwRace.STARTING ? "#e0b928":"grey" text: implicitText === "NEXT_START_ACTION" ? ["", "at your \nmarks", "ready", "starting..."][backend.race.nextStartActionDetails[ScStwRace.NextStartAction]+1]:implicitText Behavior on text { FadeAnimation { target: clickHintLabel fadeDuration: 150 } } } ProgressBar { id: nextActiondelayProgressBar anchors { left: parent.left right: parent.right bottom: parent.bottom } height: app.landscape() ? app.height * 0.1:app.width * 0.1 opacity: backend.race.nextStartActionDetails[ScStwRace.NextStartAction] < 3 && backend.race.state === ScStwRace.STARTING ? 1:0 value: backend.race.nextStartActionDetails[ScStwRace.NextStartActionDelayProgress] background: Rectangle { implicitWidth: 200 implicitHeight: parent.height color: "lightgrey" } contentItem: Item { implicitWidth: 200 implicitHeight: parent.height Rectangle { width: nextActiondelayProgressBar.visualPosition * parent.width height: parent.height color: "grey" } } Behavior on opacity { NumberAnimation { duration: 200 } } } MouseArea { parent: app anchors.fill: parent visible: controlsItm.visible enabled: visible onClicked: { switch (backend.race.state) { case ScStwRace.IDLE: // IDLE backend.race.start() break; case ScStwRace.STARTING: // STARTING backend.race.cancel() break; case ScStwRace.WAITING: // WAITING break; case ScStwRace.RUNNING: // RUNNING backend.race.stop() break; case ScStwRace.STOPPED: // STOPPED backend.race.reset() break; } } RowLayout { id: volumeSliderRow anchors { left: parent.left right: parent.right bottom: parent.bottom margins: 5 } height: app.landscape() ? app.height * 0.1:app.width * 0.12 spacing: 0 opacity: backend.race.state === ScStwRace.IDLE ? 1:0 visible: opacity > 0 Behavior on opacity { NumberAnimation { duration: 200 } } Image { Layout.preferredHeight: parent.height * 0.5 Layout.preferredWidth: height * 0.7 Layout.alignment: Layout.Center mipmap: true fillMode: Image.PreserveAspectFit source: "qrc:/VolumeLow.png" } Slider { id: volumeSlider Layout.fillHeight: true Layout.fillWidth: true implicitWidth: 200 value: parseFloat(backend.scStwClient.readRemoteSetting(ScStw.SoundVolumeSetting)) onPressedChanged: { if(!pressed){ volumeSlider.enabled = false backend.scStwClient.writeRemoteSetting(ScStw.SoundVolumeSetting, value) volumeSlider.enabled = true } } leftPadding: width * (app.landscape() ? 0.02:0.05) rightPadding: leftPadding background: Rectangle { x: volumeSlider.leftPadding y: volumeSlider.topPadding + volumeSlider.availableHeight / 2 - height / 2 implicitWidth: 200 implicitHeight: volumeSliderRow.height * 0.1 width: volumeSlider.availableWidth height: implicitHeight radius: 2 color: "#bdbebf" Rectangle { width: volumeSlider.visualPosition * parent.width height: parent.height color: "grey" radius: 2 } } handle: Item { x: volumeSlider.leftPadding - width * 0.15 + volumeSlider.visualPosition * (volumeSlider.availableWidth - width * 0.55) y: volumeSlider.topPadding + volumeSlider.availableHeight / 2 - height / 2 implicitWidth: volumeSliderRow.height implicitHeight: implicitWidth Image { anchors.fill: parent fillMode: Image.PreserveAspectFit source: "qrc:/SpeedHold.png" } } } Image { Layout.preferredHeight: parent.height * 0.5 Layout.preferredWidth: height Layout.alignment: Layout.Center mipmap: true fillMode: Image.PreserveAspectFit source: "qrc:/VolumeHigh.png" } } } states: [ State { when: [ScStwRace.IDLE,ScStwRace.STARTING].indexOf(backend.race.state) >= 0 name: "big" PropertyChanges { target: clickHintLabel anchors.margins: app.landscape() ? app.height * 0.2:app.width * 0.1 width: parent.width * 0.7 height: parent.height * 0.7 } PropertyChanges { target: controlsItm height: app.height } }, State { when: [ScStwRace.IDLE,ScStwRace.STARTING].indexOf(backend.race.state) < 0 name: "small" PropertyChanges { target: clickHintLabel anchors.margins: app.landscape() ? app.height * 0.01:app.width * 0.1 } PropertyChanges { target: controlsItm height: app.landscape() ? app.height * 0.2:app.height * 0.4 } } ] transitions: [ Transition { from: "*" to: "*" PauseAnimation { duration: 150 } } ] } } } Component { id: loadingComp Item { id: loadingItm anchors.fill: parent FancyBusyIndicator { id: loadingInd anchors.centerIn: parent width: app.landscape() ? parent.height * 0.2 : parent.width *0.2 height: width } TextField { id: ipAddrInputTf anchors { bottom: parent.bottom horizontalCenter: parent.horizontalCenter } opacity: backend.scStwClient.state === ScStwClient.CONNECTED ? 0:1 text: appSettings.baseStationIp onEditingFinished: { appSettings.baseStationIp = text backend.scStwClient.ipAddress = text } } } } } }