app/resources/qml/Components/SpeedFlowChart.qml

348 lines
14 KiB
QML

/*
blueROCK - for digital rock
Copyright (C) 2019 Dorian Zedler
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.10
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.1
import QtGraphicalEffects 1.0
import "SpeedFlowChart.js" as SpeedFlowChart
Item {
id: control
property var flowchartData
property var allFlowchartData
property int rounds: 0
property int refreshes: 0
property int roundRefreshes: 1
onFlowchartDataChanged: {
prepareData()
}
function prepareData() {
if(!control.enabled || control.flowchartData === undefined || control.flowchartData['route_names'] === undefined)
return
var flowchartResult = SpeedFlowChart.convertResultsToSpeedFlowchartResult(control.flowchartData)
const l = flowchartResult.rounds.length;
const dummy = { dummy: true };
flowchartResult.rounds[l - 2].pairs = [
dummy,
...flowchartResult.rounds[l - 1].pairs,
...flowchartResult.rounds[l - 2].pairs,
];
flowchartResult.rounds[l - 2].roundName = `${
flowchartResult.rounds[l - 1].roundName
} / ${flowchartResult.rounds[l - 2].roundName}`;
flowchartResult.rounds.pop();
control.allFlowchartData = flowchartResult
}
ListView {
id: roundListView
property int columnWidth: height * 0.4
property int columnHeight: height
anchors {
top: parent.top
bottom: parent.bottom
horizontalCenter: parent.horizontalCenter
}
width: Math.min((columnWidth + spacing) * model, control.width)
spacing: app.height * 0.05
orientation: ListView.LeftToRight
boundsBehavior: ListView.StopAtBounds
model: control.allFlowchartData.rounds.length
delegate: Item {
id: roundItem
property int thisIndex: index
property var thisData: control.allFlowchartData.rounds[thisIndex]
property bool thisRoundIsValid: true
property bool thisIsLastRound: thisIndex === roundListView.model - 1
property bool thisIsSemiFinal: thisIndex === roundListView.model - 2
property int tileSize: (roundItem.height / 8 - roundNameLa.height) * 1.45
width: roundListView.columnWidth
height: roundListView.columnHeight
Column {
id: roundCol
anchors.fill: parent
Label {
id: roundNameLa
width: parent.width
height: control.height * 0.05
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
fontSizeMode: Text.Fit
font.pixelSize: height * 0.6
minimumPixelSize: 1
font.bold: true
text: roundItem.thisData.roundName ?
roundItem.thisData.roundName :
"-"
}
Repeater {
id: rectRep
model: roundItem.thisData.pairs.length
delegate: Item {
id: matchItm
property bool lowerPart: (index%2 > 0)
property var thisData: roundItem.thisData.pairs[index]
property int thisIndex: index
height: (roundItem.height - roundNameLa.height) / rectRep.model - roundCol.spacing
width: roundItem.width
onThisDataChanged: {
fadeInPa.start()
}
ParallelAnimation {
id: fadeInPa
NumberAnimation { target: matchItm; property: "opacity"; from: 0; to: 1.0; duration: 400 }
NumberAnimation { target: matchItm; property: "scale"; from: 0.8; to: 1.0; duration: 400 }
}
Canvas {
id: lineCanvas
width: app.width; height: app.height
contextType: "2d"
visible: !roundItem.thisIsLastRound
property int targetYFactor: matchItm.lowerPart ? -1:1
Path {
id: firstPartPath
startX: matchItm.width
startY: matchItm.height * 0.5
PathQuad {
id: firstPartPathQuad
relativeX: roundListView.spacing * 0.5
relativeY: matchItm.height * 0.25 * lineCanvas.targetYFactor
relativeControlX: relativeX
relativeControlY: 0
}
PathQuad {
relativeX: roundListView.spacing * 0.5
relativeY: matchItm.height * 0.25 * lineCanvas.targetYFactor
relativeControlX: 0
relativeControlY: relativeY
}
}
onPaint: {
context.strokeStyle = "lightgrey"
context.lineWidth = matchRect.height * 0.05
context.path = firstPartPath;
context.stroke();
}
}
RectangularGlow {
id: effect
visible: matchRect.visible
anchors.fill: matchRect
glowRadius: 0
spread: 0
opacity: 0.3
color: "black"
cornerRadius: matchRect.radius
}
Rectangle {
id: matchRect
anchors {
centerIn: !matchItm.thisIsFinal ? parent:undefined
bottom: matchItm.thisIsFinal ? parent.bottom:undefined
}
visible: !matchItm.thisData.dummy
width: parent.width
height: roundItem.tileSize
color: Material.dialogColor
radius: height * 0.2
Column {
spacing: 0
anchors.fill: parent
anchors.margins: matchRect.radius * 0.5
Repeater {
// for the two athletes
model: 2
delegate: RowLayout {
id: laneRow
property var thisData: index === 0 ? matchItm.thisData.laneA : matchItm.thisData.laneB
property var participant: thisData ? thisData.participant : undefined
property var result: thisData ? thisData.result : undefined
property var lane: index === 0 ? "A":"B"
property bool isWinner: matchItm.thisData.winner === laneRow.lane
height: parent.height / 2 - parent.spacing
width: parent.width
spacing: height * 0.1
Label {
Layout.preferredHeight: parent.height
Layout.preferredWidth: parent.width * 0.08
height: parent.height
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.pixelSize: height * 0.4
font.bold: true
opacity: 0.7
text: laneRow.participant ?
(
laneRow.participant.results[0].rank < 10 ?
laneRow.participant.results[0].rank + " ":
laneRow.participant.results[0].rank
):
""
}
Label {
Layout.preferredHeight: parent.height
Layout.maximumWidth: parent.width * 0.6
height: parent.height
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.pixelSize: height * 0.5
font.bold: laneRow.isWinner
elide: "ElideRight"
color: laneRow.isWinner ? Material.color(Material.Green):Material.primaryTextColor
text: laneRow.participant ? laneRow.participant.firstName + " " + laneRow.participant.lastName :"-"
}
Rectangle {
Layout.preferredHeight: parent.height * 0.8
Layout.preferredWidth: parent.width * 0.13
visible: laneRow.participant && laneRow.participant.startNumber ? true:false
radius: height / 2
border.width: parent.height * 0.03
border.color: Material.frameColor
color: "transparent"
Label {
anchors.fill: parent
padding: parent.parent.height * 0.1
leftPadding: padding * 2
rightPadding: leftPadding
font.pixelSize: parent.height * 0.5
font.bold: true
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: laneRow.participant ? laneRow.participant.startNumber:""
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
}
Label {
Layout.preferredHeight: parent.height
Layout.preferredWidth: parent.width * 0.15
height: parent.height
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignRight
font.pixelSize: height * 0.5
font.bold: laneRow.isWinner
color: laneRow.isWinner ? Material.color(Material.Green):Material.primaryTextColor
text: laneRow.result ? laneRow.result.result : ""
}
}
}
}
}
}
}
}
Loader {
id: blueRockBadgeLoader
x: (parent.width - width) / 2
y: (parent.height - roundNameLa.height - height) / 2 + roundNameLa.height
sourceComponent: roundItem.thisIsSemiFinal ? blueRockBadgeComponent:undefined
Component {
id: blueRockBadgeComponent
BlueRockBadge {
width: roundItem.width * 0.8
height: width * 0.25
}
}
}
}
}
}