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 import de.itsblue.ScStw.Styling 2.0 import ScStwQmlComponents 1.0 Window { id: window visible: true width: XscreenWidth / 2 height: XscreenHeight / 2 title: qsTr("ScStwMonitor") //visibility: Window.FullScreen Page { id: app anchors.fill: parent background: Rectangle { color: appTheme.theme.colors.background } function landscape() { return app.width > app.height } ScStwMonitorBackend { id: backend scStwClient.ipAddress: appSettings.baseStationIp } ScStwAppThemeManager { id: appTheme Component.onCompleted: { appTheme.setTheme("Light") } } 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 } } } 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 timers: backend.race.timers colors: appTheme.theme.colors fontName: appTheme.theme.fonts.timers 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 ? appTheme.theme.colors.warning:appTheme.theme.colors.text 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 } } Icon { Layout.preferredHeight: parent.height * 0.7 Layout.preferredWidth: height * 0.7 Layout.alignment: Layout.Center fontName: appTheme.theme.fonts.icons icon: appTheme.theme.icons.volumeDown color: appTheme.theme.colors.text } 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" } } } Icon { Layout.preferredHeight: parent.height * 0.7 Layout.preferredWidth: height * 0.7 Layout.alignment: Layout.Center fontName: appTheme.theme.fonts.icons icon: appTheme.theme.icons.volumeUp color: appTheme.theme.colors.text } } } 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 BusyIndicator { 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 } } } } } }