diff --git a/src/charts/qml/AnalyzeDialog.qml b/src/charts/qml/AnalyzeDialog.qml index 637a4610af6c71144f8cc3f4b4e7e97c74ee65ef..4bafb48862eef65bdd1a67e74d2ed1ef1ae6e1b2 100644 --- a/src/charts/qml/AnalyzeDialog.qml +++ b/src/charts/qml/AnalyzeDialog.qml @@ -2,254 +2,419 @@ * Copyright (C) 2018-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" +import Nootka 1.0 +import Nootka.Charts 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Window 2.12 -import Nootka 1.0 -import Nootka.Charts 1.0 -import "../" +Window { + id: analyzeWindow + property alias exam: chartItem.exam + property alias allowOpen: chartItem.allowOpen + //* private + property var helpTip: null + property int upTextSize: Math.round(toolBar.height * 0.25) + property var chDrawer: null -Window { - id: analyzeWindow - - property alias exam: chartItem.exam - property alias allowOpen: chartItem.allowOpen - - /** private */ - property var helpTip: null - property int upTextSize: Math.round(toolBar.height * 0.25) - property var chDrawer: null - - function openExam() { - if (allowOpen) - chartItem.openExam() - } - - function openDrawer() { drawerAct.trigger() } - - visible: true - modality: Qt.WindowModal - title: chartItem.chartWindowTitle - width: nootkaWindow.width; height: nootkaWindow.height; x: nootkaWindow.x; y: nootkaWindow.y - color: activPal.base - - ButtonGroup { id: chartTypeGr } - - Column { - ToolBar { - id: toolBar - z: 255 - height: helpButt.height; width: analyzeWindow.width - background: TipRect { anchors.fill: parent; color: activPal.window; radius: 0 } - Row { - ChartToolButton { - taction: Taction { - id: drawerAct - text: qsTr("Settings of a chart"); icon: "chartSett" - onTriggered: { - if (chDrawer) { - if (chDrawer.visible) - chDrawer.close() - else - chDrawer.open() - } else { - var d = Qt.createComponent("qrc:/charts/ChartDrawer.qml") - chDrawer = d.createObject(analyzeWindow) - } - } - } - } - ChartToolButton { - taction: Taction { - text: NOO.TR("QShortcut", "Zoom In"); icon: "zoom-in"; shortcut: Shortcut { sequence: StandardKey.ZoomIn } - onTriggered: chartView.sc = Math.min(2.0, chartView.sc * 1.125) - } - } - ChartToolButton { - taction: Taction { - text: NOO.TR("QShortcut", "Zoom Out"); icon: "zoom-out"; shortcut: Shortcut { sequence: StandardKey.ZoomOut } - onTriggered: chartView.sc = Math.max(0.5, chartView.sc * 0.888889) - } - } - ChartToolButton { - taction: Taction { - text: NOO.TR("QMdiSubWindow", "Maximize"); icon: "fullscreen" - onTriggered: visibility = visibility === 2 ? 4 : 2 - } - } - ChartToolButton { - id: helpButt - taction: Taction { - text: NOO.TR("QShortcut", "Help"); icon: "help" - onTriggered: NOO.openDocLink("2017/05/17/analyze-results/") - } + function openExam() { + if (allowOpen) + chartItem.openExam(); + } + + function openDrawer() { + drawerAct.trigger(); + } + + visible: true + modality: Qt.WindowModal + title: chartItem.chartWindowTitle + width: nootkaWindow.width + height: nootkaWindow.height + x: nootkaWindow.x + y: nootkaWindow.y + color: activPal.base + + onClosing: { + SOUND.startListen(); + analyzeWindow.destroy(); + } + + Component.onCompleted: { + if (allowOpen) { + var h = Qt.createComponent("qrc:/charts/ChartHelpTip.qml"); + helpTip = h.createObject(analyzeWindow.contentItem, { + "text": chartItem.chartHelpText() + }); } - Item { height: 2; width: (analyzeWindow.width - (helpButt.x + helpButt.width) - exitButt.width - infoRow.width) / 2 } - - Row { - id: infoRow -// visible: chartItem.questionCount > 0 - Column { - visible: chartItem.isMelody // && chartItem.questionCount > 0 - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("Y value:") - font { pixelSize: upTextSize } - color: activPal.text; verticalAlignment: Text.AlignVCenter - height: toolBar.height * 0.48 - } - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: chartItem.yValueActions[chartItem.yValue] - font { pixelSize: upTextSize; bold: true } - color: activPal.text; verticalAlignment: Text.AlignVCenter; horizontalAlignment: Text.AlignHCenter - height: toolBar.height * 0.48; width: analyzeWindow.width / 7 - fontSizeMode: Text.Fit; minimumPixelSize: NOO.factor() / 2 - } - } - Item { height: 2; width: analyzeWindow.width / 100 } - Column { - visible: !chartItem.isMelody //&& chartItem.questionCount > 0 - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("ordered by:", "Keep a proper form - whole sentence will be: ordered by: question number, key signature, etc...") - font { pixelSize: upTextSize } - color: activPal.text; verticalAlignment: Text.AlignVCenter; horizontalAlignment: Text.AlignHCenter - height: toolBar.height * 0.48; width: analyzeWindow.width / 7 - } - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: chartItem.xOrderActions[chartItem.xOrder] - font { pixelSize: upTextSize; bold: true } - color: activPal.text; verticalAlignment: Text.AlignVCenter; horizontalAlignment: Text.AlignHCenter - height: toolBar.height * 0.48; width: analyzeWindow.width / 7 - fontSizeMode: Text.Fit; minimumPixelSize: NOO.factor() / 2 - } - } - Item { height: 2; width: analyzeWindow.width / 100 } - Column { - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("student name:") - font { pixelSize: upTextSize } - color: activPal.text; verticalAlignment: Text.AlignVCenter - height: toolBar.height * 0.5 - } - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: chartItem.userName === "" ? "-----" : chartItem.userName - font { pixelSize: toolBar.height / 4; bold: true } - color: activPal.text; verticalAlignment: Text.AlignVCenter - height: toolBar.height * 0.5 + SOUND.stop(); + if (chartItem.keepDrawerOpened()) + openDrawer(); + } + + ButtonGroup { + id: chartTypeGr + } + + Column { + property TchartItem chartItem + + chartItem: TchartItem { + id: chartItem + + parent: chartView + anchors.fill: parent + onExamChanged: { + if (helpTip && exam) + helpTip.destroy(); + + if (tipItem) + tipItem.parent.destroy(); + + tipItem = Qt.createComponent("qrc:/charts/ChartTip" + (isMelody ? "Melody" : "") + ".qml").createObject(chartView.list).tipItem; } - } - Item { height: 2; width: analyzeWindow.width / 100 } - Column { - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("level:") - font { pixelSize: upTextSize } - color: activPal.text; verticalAlignment: Text.AlignVCenter - height: toolBar.height * 0.5 + onResetChartPos: chartView.list.positionViewAtBeginning() + onLoadExamFailed: { + if (!helpTip) + helpTip = Qt.createComponent("qrc:/charts/ChartHelpTip.qml").createObject(analyzeWindow.contentItem); + helpTip.text = message; + helpTip.hintColor = GLOB.wrongColor; } - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - width: levelText.width + NOO.factor(); height: toolBar.height / 2 - color: levelArea.containsMouse ? activPal.highlight : "transparent" - radius: height / 5 - Text { - id: levelText - anchors.centerIn: parent - text: chartItem.levelName === "" ? "-----" : chartItem.levelName - font { pixelSize: toolBar.height / 4; bold: true } - color: activPal.text - } - MouseArea { - id: levelArea - hoverEnabled: chartItem.levelName !== "" - anchors.fill: parent - onClicked: { - var c = Qt.createComponent("qrc:/charts/LevelPopup.qml") - var lp = c.createObject(analyzeWindow.contentItem) - chartItem.fillPreview(lp.levelPreview) + } + + ToolBar { + id: toolBar + + z: 255 + height: helpButt.height + width: analyzeWindow.width + + Row { + ChartToolButton { + + taction: Taction { + id: drawerAct + + text: qsTr("Settings of a chart") + icon: "chartSett" + onTriggered: { + if (chDrawer) { + if (chDrawer.visible) + chDrawer.close(); + else + chDrawer.open(); + } else { + var d = Qt.createComponent("qrc:/charts/ChartDrawer.qml"); + chDrawer = d.createObject(analyzeWindow); + } + } + } } - } - } - } - Item { height: 2; width: analyzeWindow.width / 100 } - Column { - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: chartItem.questionCount - font { pixelSize: upTextSize } - color: activPal.text; horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - height: toolBar.height * 0.5 + + ChartToolButton { + + taction: Taction { + text: NOO.TR("QShortcut", "Zoom In") + icon: "zoom-in" + onTriggered: chartView.sc = Math.min(2, chartView.sc * 1.125) + + shortcut: Shortcut { + sequences: [ StandardKey.ZoomIn ] + } + } + + } + + ChartToolButton { + + taction: Taction { + text: NOO.TR("QShortcut", "Zoom Out") + icon: "zoom-out" + onTriggered: chartView.sc = Math.max(0.5, chartView.sc * 0.888889) + + shortcut: Shortcut { + sequence: StandardKey.ZoomOut + } + + } + + } + + ChartToolButton { + + taction: Taction { + text: NOO.TR("QMdiSubWindow", "Maximize") + icon: "fullscreen" + onTriggered: visibility = visibility === 2 ? 4 : 2 + } + + } + + ChartToolButton { + id: helpButt + + taction: Taction { + text: NOO.TR("QShortcut", "Help") + icon: "help" + onTriggered: NOO.openDocLink("2017/05/17/analyze-results/") + } + + } + + Item { + height: 2 + width: (analyzeWindow.width - (helpButt.x + helpButt.width) - exitButt.width - infoRow.width) / 2 + } + + Row { + id: infoRow + + // visible: chartItem.questionCount > 0 + Column { + visible: chartItem.isMelody // && chartItem.questionCount > 0 + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Y value:") + color: activPal.text + verticalAlignment: Text.AlignVCenter + height: toolBar.height * 0.48 + + font { + pixelSize: upTextSize + } + + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: chartItem.yValueActions[chartItem.yValue] + color: activPal.text + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + height: toolBar.height * 0.48 + width: analyzeWindow.width / 7 + fontSizeMode: Text.Fit + minimumPixelSize: NOO.factor() / 2 + + font { + pixelSize: upTextSize + bold: true + } + + } + + } + + Item { + height: 2 + width: analyzeWindow.width / 100 + } + + Column { + visible: !chartItem.isMelody //&& chartItem.questionCount > 0 + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("ordered by:", "Keep a proper form - whole sentence will be: ordered by: question number, key signature, etc...") + color: activPal.text + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + height: toolBar.height * 0.48 + width: analyzeWindow.width / 7 + + font { + pixelSize: upTextSize + } + + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: chartItem.xOrderActions[chartItem.xOrder] + color: activPal.text + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + height: toolBar.height * 0.48 + width: analyzeWindow.width / 7 + fontSizeMode: Text.Fit + minimumPixelSize: NOO.factor() / 2 + + font { + pixelSize: upTextSize + bold: true + } + + } + + } + + Item { + height: 2 + width: analyzeWindow.width / 100 + } + + Column { + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("student name:") + color: activPal.text + verticalAlignment: Text.AlignVCenter + height: toolBar.height * 0.5 + + font { + pixelSize: upTextSize + } + + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: chartItem.userName === "" ? "-----" : chartItem.userName + color: activPal.text + verticalAlignment: Text.AlignVCenter + height: toolBar.height * 0.5 + + font { + pixelSize: toolBar.height / 4 + bold: true + } + + } + + } + + Item { + height: 2 + width: analyzeWindow.width / 100 + } + + Column { + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("level:") + color: activPal.text + verticalAlignment: Text.AlignVCenter + height: toolBar.height * 0.5 + + font { + pixelSize: upTextSize + } + + } + + Rectangle { + anchors.horizontalCenter: parent.horizontalCenter + width: levelText.width + NOO.factor() + height: toolBar.height / 2 + color: levelArea.containsMouse ? activPal.highlight : "transparent" + radius: height / 5 + + Text { + id: levelText + + anchors.centerIn: parent + text: chartItem.levelName === "" ? "-----" : chartItem.levelName + color: activPal.text + + font { + pixelSize: toolBar.height / 4 + bold: true + } + + } + + MouseArea { + id: levelArea + + hoverEnabled: chartItem.levelName !== "" + anchors.fill: parent + onClicked: { + var c = Qt.createComponent("qrc:/charts/LevelPopup.qml"); + var lp = c.createObject(analyzeWindow.contentItem); + chartItem.fillPreview(lp.levelPreview); + } + } + + } + + } + + Item { + height: 2 + width: analyzeWindow.width / 100 + } + + Column { + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: chartItem.questionCount + color: activPal.text + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + height: toolBar.height * 0.5 + + font { + pixelSize: upTextSize + } + + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: chartItem.effectiveness + color: activPal.text + horizontalAlignment: Text.AlignHCenter + + font { + pixelSize: toolBar.height / 4 + } + + } + + } + // Row (infoRow) + + } + // Row + } - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: chartItem.effectiveness - font { pixelSize: toolBar.height / 4 } - color: activPal.text; horizontalAlignment: Text.AlignHCenter + + ChartToolButton { + id: exitButt + + anchors.right: parent.right + + taction: Taction { + text: NOO.TR("QPlatformTheme", "Close") + icon: "exit" + onTriggered: close() + } + } - } - } // Row (infoRow) - } // Row + background: TipRect { + anchors.fill: parent + color: activPal.window + radius: 0 + } - ChartToolButton { - id: exitButt - anchors.right: parent.right - taction: Taction { - text: NOO.TR("QPlatformTheme", "Close"); icon: "exit" - onTriggered: close() } - } - } - property TchartItem chartItem: TchartItem { - id: chartItem - parent: chartView; anchors.fill: parent - onExamChanged: { - if (helpTip && exam) - helpTip.destroy() - if (tipItem) - tipItem.parent.destroy() - tipItem = Qt.createComponent("qrc:/charts/ChartTip" + (isMelody ? "Melody" : "") + ".qml").createObject(chartView.list).tipItem - } - onResetChartPos: chartView.list.positionViewAtBeginning() - onLoadExamFailed: { - if (!helpTip) - helpTip = Qt.createComponent("qrc:/charts/ChartHelpTip.qml").createObject(analyzeWindow.contentItem) - helpTip.text = message - helpTip.hintColor = GLOB.wrongColor - } - } + ChartView { + id: chartView - ChartView { - id: chartView - width: analyzeWindow.width - (chDrawer && chDrawer.pinned && chDrawer.visible ? chDrawer.width : 0) - height: analyzeWindow.height - toolBar.height - transform: Translate { - x: chDrawer ? chDrawer.position * analyzeWindow.height * 0.4 : 0 - } - } - } + width: analyzeWindow.width - (chDrawer && chDrawer.pinned && chDrawer.visible ? chDrawer.width : 0) + height: analyzeWindow.height - toolBar.height - onClosing: { - SOUND.startListen() - analyzeWindow.destroy() - } + transform: Translate { + x: chDrawer ? chDrawer.position * analyzeWindow.height * 0.4 : 0 + } + + } - Component.onCompleted: { - if (allowOpen) { - var h = Qt.createComponent("qrc:/charts/ChartHelpTip.qml") - helpTip = h.createObject(analyzeWindow.contentItem, { "text": chartItem.chartHelpText() } ) } - SOUND.stop() - if (chartItem.keepDrawerOpened()) - openDrawer() - } + } diff --git a/src/charts/qml/BarDelegate.qml b/src/charts/qml/BarDelegate.qml index 82de2db85f4d913fe056cb8808633cbf99c5ccd9..c0bc92abbd0d99da979232d06287219367d2bfdc 100644 --- a/src/charts/qml/BarDelegate.qml +++ b/src/charts/qml/BarDelegate.qml @@ -2,64 +2,103 @@ * Copyright (C) 2019-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 -import Qt5Compat.GraphicalEffects - import Nootka 1.0 import Nootka.Charts 1.0 - +import Qt5Compat.GraphicalEffects +import QtQuick 2.12 Item { - id: barDel - - property alias chart: barIt.chart - property alias groupNr: barIt.groupNr - - TbarChartDelegate { - id: barIt - x: parent.width * 0.75 - y: parent.height * 0.1 + maxDataHeight - (yValue / chartItem.maxYValue()) * maxDataHeight - width: parent.width / 2; height: maxDataHeight * 1.14 - y - visible: false - hovered: barMA.containsMouse - } - DropShadow { - z: 5010 - anchors.fill: barIt - horizontalOffset: barDel.width / 30 - verticalOffset: horizontalOffset - radius: NOO.factor() * (barIt.hovered ? 2 : 1) - samples: 1 + radius * 2 - color: activPal.shadow - source: barIt - Behavior on radius { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - scale: barMA.containsMouse ? 1.1 : 1.0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - MouseArea { - id: barMA - anchors.fill: parent - hoverEnabled: true + id: barDel + + property alias chart: barIt.chart + property alias groupNr: barIt.groupNr + + TbarChartDelegate { + id: barIt + + x: parent.width * 0.75 + y: parent.height * 0.1 + maxDataHeight - (yValue / chartItem.maxYValue()) * maxDataHeight + width: parent.width / 2 + height: maxDataHeight * 1.14 - y + visible: false + hovered: barMA.containsMouse + } + + DropShadow { + z: 5010 + anchors.fill: barIt + horizontalOffset: barDel.width / 30 + verticalOffset: horizontalOffset + radius: NOO.factor() * (barIt.hovered ? 2 : 1) + samples: 1 + radius * 2 + color: activPal.shadow + source: barIt + scale: barMA.containsMouse ? 1.1 : 1 + + MouseArea { + id: barMA + + anchors.fill: parent + hoverEnabled: true + } + + Behavior on radius { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + } - } - - Rectangle { // X axis line (partial) - color: activPal.text - y: parent.height - width + lThick / 2 - width: parent.width; height: lThick - Rectangle { // X tick - color: activPal.text - x: parent.width - lThick; y: lThick - width: lThick; height: lThick * 2 - Column { // X value (description) - y: lThick * 2 - anchors.horizontalCenter: parent.horizontalCenter - Text { - text: barIt.xText; font { pixelSize: barDel.width / 5 } - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text; textFormat: Text.RichText; horizontalAlignment: Text.AlignHCenter + + // X axis line (partial) + Rectangle { + color: activPal.text + y: parent.height - width + lThick / 2 + width: parent.width + height: lThick + + // X tick + Rectangle { + color: activPal.text + x: parent.width - lThick + y: lThick + width: lThick + height: lThick * 2 + + // X value (description) + Column { + y: lThick * 2 + anchors.horizontalCenter: parent.horizontalCenter + + Text { + text: barIt.xText + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + textFormat: Text.RichText + horizontalAlignment: Text.AlignHCenter + + font { + pixelSize: barDel.width / 5 + } + + } + + } + } - } + } - } } diff --git a/src/charts/qml/ChartDrawer.qml b/src/charts/qml/ChartDrawer.qml index df5a2ad2ec458c18237b2de4d1eba435f1860308..12d3ba62f9ca1bf1173c93add36bc6edc2636566 100644 --- a/src/charts/qml/ChartDrawer.qml +++ b/src/charts/qml/ChartDrawer.qml @@ -2,192 +2,306 @@ * Copyright (C) 2019-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Window 2.12 -import Nootka 1.0 -import "../" +Drawer { + // Tflickable + id: chartDrawer -Drawer { - id: chartDrawer - - property alias pinned: pinBox.checked - - visible: true - modal: false - y: analyzeWindow.height / 15 + Screen.pixelDensity * 2 - width: parent.height * 0.4; height: parent.height - y - - closePolicy: chartItem.keepDrawerOpened() ? Popup.NoAutoClose : Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: TipRect { color: activPal.window; radius: 0; verticalOffset: 0; horizontalOffset: pinBox.checked ? 0 : NOO.factor() / 5 } - - property int fSize: Math.min(NOO.factor(), width / 25) - - Connections { - target: chartItem - onLockXorderList: orderCombo.lock(itNr, state) - } - - Tflickable { - height: parent.height - contentHeight: drawCol.height - - Column { - id: drawCol - width: parent.width; spacing: fSize / 2 - - Column { - visible: chartItem.allowOpen - width: parent.width - MenuButton { width: parent.width; action: chartItem.loadExamAct() } - ListView { - id: recentList - width: parent.width; height: Math.min(NOO.factor() * 16.8, NOO.factor() * count * 2.8) // 6 items visible - boundsBehavior: Flickable.StopAtBounds - contentHeight: NOO.factor() * count * 2.8 - model: chartItem.recentExamsActions - currentIndex: chartItem.selectedFileId - clip: true - delegate: MenuButton { - width: parent ? parent.width : 0 - action: modelData - color: containsPress || recentList.currentIndex === index ? activPal.highlight : - (containsMouse ? NOO.alpha(activPal.highlight, 50) : (index % 2 ? activPal.alternateBase : activPal.base)) - textColor: containsPress || recentList.currentIndex === index ? activPal.highlightedText : activPal.text - Rectangle { width: parent.width; height: 1; color: activPal.window; y: parent.height - 1; } - } - ScrollBar.vertical: ScrollBar { active: true; visible: true } - } - MenuButton { - visible: chartItem.exerciseAct(); width: parent.width; action: chartItem.exerciseAct() - Rectangle { width: parent.width; height: 1; color: activPal.dimText; y: parent.height - 1; } - } - } - - Item { visible: !chartItem.isMelody; width: parent.width; height: fSize } - - Row { - visible: !chartItem.isMelody - spacing: fSize / 4 - anchors.horizontalCenter: parent.horizontalCenter - TradioButton { - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: fSize - checked: chartItem.chartType === 0 - onClicked: chartItem.chartType = checked ? 0 : 1 - } - Text { - text: qsTranslate("AnalyzeDialog", "linear chart").replace(" ", "\n") - anchors.verticalCenter: parent.verticalCenter - color: activPal.text; font.pixelSize: fSize - } - Item { width: chartDrawer.width / 10; height: 1 } - TradioButton { - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: fSize - onClicked: chartItem.chartType = checked ? 1 : 0 - } - Text { - text: qsTranslate("AnalyzeDialog", "bar chart").replace(" ", "\n") - anchors.verticalCenter: parent.verticalCenter - color: activPal.text; font.pixelSize: fSize - } - } + property alias pinned: pinBox.checked + property int fSize: Math.min(NOO.factor(), width / 25) + + visible: true + modal: false + y: analyzeWindow.height / 15 + Screen.pixelDensity * 2 + width: parent.height * 0.4 + height: parent.height - y + closePolicy: chartItem.keepDrawerOpened() ? Popup.NoAutoClose : Popup.CloseOnEscape | Popup.CloseOnPressOutside + + Connections { + target: chartItem + function onLockXorderList(itNr: int, state: bool) : void { orderCombo.lock(itNr, state) } + } + + Tflickable { + height: parent.height + contentHeight: drawCol.height + + Column { + id: drawCol + + width: parent.width + spacing: fSize / 2 + + Column { + visible: chartItem.allowOpen + width: parent.width + + MenuButton { + width: parent.width + action: chartItem.loadExamAct() + } + + ListView { + id: recentList + + width: parent.width // 6 items visible + height: Math.min(NOO.factor() * 16.8, NOO.factor() * count * 2.8) + boundsBehavior: Flickable.StopAtBounds + contentHeight: NOO.factor() * count * 2.8 + model: chartItem.recentExamsActions + currentIndex: chartItem.selectedFileId + clip: true + + delegate: MenuButton { + width: parent ? parent.width : 0 + action: modelData + color: containsPress || recentList.currentIndex === index ? activPal.highlight : (containsMouse ? NOO.alpha(activPal.highlight, 50) : (index % 2 ? activPal.alternateBase : activPal.base)) + textColor: containsPress || recentList.currentIndex === index ? activPal.highlightedText : activPal.text + + Rectangle { + width: parent.width + height: 1 + color: activPal.window + y: parent.height - 1 + } + + } + + ScrollBar.vertical: ScrollBar { + active: true + visible: true + } + + } + + MenuButton { + visible: chartItem.exerciseAct() + width: parent.width + action: chartItem.exerciseAct() + + Rectangle { + width: parent.width + height: 1 + color: activPal.dimText + y: parent.height - 1 + } + + } + + } + + Item { + visible: !chartItem.isMelody + width: parent.width + height: fSize + } + + Row { + visible: !chartItem.isMelody + spacing: fSize / 4 + anchors.horizontalCenter: parent.horizontalCenter + + TradioButton { + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: fSize + checked: chartItem.chartType === 0 + onClicked: chartItem.chartType = checked ? 0 : 1 + } + + Text { + text: qsTranslate("AnalyzeDialog", "linear chart").replace(" ", "\n") + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + font.pixelSize: fSize + } + + Item { + width: chartDrawer.width / 10 + height: 1 + } + + TradioButton { + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: fSize + onClicked: chartItem.chartType = checked ? 1 : 0 + } + + Text { + text: qsTranslate("AnalyzeDialog", "bar chart").replace(" ", "\n") + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + font.pixelSize: fSize + } + + } - Item { width: parent.width; height: fSize } + Item { + width: parent.width + height: fSize + } + + Column { + visible: !chartItem.isMelody + width: parent.width + spacing: fSize / 2 + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: qsTranslate("AnalyzeDialog", "ordered by:", "Keep a proper form - whole sentence will be: ordered by: question number, key signature, etc...") + color: activPal.text + font.pixelSize: fSize + } + + TcomboBox { + id: orderCombo + + width: Math.min(parent.width - fSize, NOO.factor() * 20) + font.pixelSize: fSize + anchors.horizontalCenter: parent.horizontalCenter + model: chartItem.xOrderActions + currentIndex: chartItem.xOrder + onActivated: index => { chartItem.xOrder = index } + } + + } + + Column { + visible: chartItem.isMelody + width: parent.width + spacing: fSize / 2 + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: qsTranslate("AnalyzeDialog", "Y value:") + color: activPal.text + font.pixelSize: fSize + } + + TcomboBox { + width: Math.min(parent.width - fSize, NOO.factor() * 20) + font.pixelSize: fSize + anchors.horizontalCenter: parent.horizontalCenter + model: chartItem.yValueActions + currentIndex: chartItem.yValue + onActivated: chartItem.yValue = index + } + + } + + Item { + width: parent.width + height: fSize + } + + Column { + width: parent.width + spacing: fSize / 2 + + Repeater { + model: chartItem.miscSettModel + + Row { + spacing: fSize / 2 + enabled: modelData.enabled + + TcheckBox { + font.pixelSize: fSize + anchors.verticalCenter: parent.verticalCenter + checked: modelData.checked + onClicked: modelData.trigger() + } + + Text { + width: chartDrawer.width - fSize * 4 + anchors.verticalCenter: parent.verticalCenter + wrapMode: Text.Wrap + text: modelData.text + color: enabled ? activPal.text : disdPal.text + font.pixelSize: fSize + } + + } + + } + + } - Column { - visible: !chartItem.isMelody - width: parent.width; spacing: fSize / 2 - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: qsTranslate("AnalyzeDialog", "ordered by:", "Keep a proper form - whole sentence will be: ordered by: question number, key signature, etc...") - color: activPal.text; font.pixelSize: fSize } - TcomboBox { - id: orderCombo - width: Math.min(parent.width - fSize, NOO.factor() * 20) - font.pixelSize: fSize - anchors.horizontalCenter: parent.horizontalCenter - model: chartItem.xOrderActions - currentIndex: chartItem.xOrder - onActivated: chartItem.xOrder = index + + // Column + ScrollBar.horizontal: ScrollBar { + active: true + visible: true } - } - - Column { - visible: chartItem.isMelody - width: parent.width; spacing: fSize / 2 - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: qsTranslate("AnalyzeDialog", "Y value:") - color: activPal.text; font.pixelSize: fSize + + } + + TcheckBox { + id: pinBox + + hoverEnabled: true + font.pixelSize: fSize + checked: chartItem.keepDrawerOpened() + onClicked: { + chartDrawer.closePolicy = checked ? Popup.NoAutoClose : Popup.CloseOnEscape | Popup.CloseOnPressOutside; + chartItem.setKeepDrawer(checked); } - TcomboBox { - width: Math.min(parent.width - fSize, NOO.factor() * 20) - font.pixelSize: fSize - anchors.horizontalCenter: parent.horizontalCenter - model: chartItem.yValueActions - currentIndex: chartItem.yValue - onActivated: chartItem.yValue = index + + anchors { + right: parent.right + bottom: parent.bottom } - } - Item { width: parent.width; height: fSize } + ToolTip { + delay: 500 + timeout: 5000 + visible: pinBox.hovered - Column { - width: parent.width; spacing: fSize / 2 - Repeater { - model: chartItem.miscSettModel - Row { - spacing: fSize / 2 - enabled: modelData.enabled - TcheckBox { - font.pixelSize: fSize - anchors.verticalCenter: parent.verticalCenter - checked: modelData.checked - onClicked: modelData.trigger() + contentItem: Text { + text: qsTr("keep opened") + color: activPal.highlightedText } - Text { - width: chartDrawer.width - fSize * 4 - anchors.verticalCenter: parent.verticalCenter - wrapMode: Text.Wrap - text: modelData.text - color: enabled ? activPal.text : disdPal.text; font.pixelSize: fSize + + enter: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 1 + } + } - } + + exit: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 0 + } + + } + + background: TipRect { + shadowRadius: NOO.factor() + color: activPal.highlight + } + } - } - - } // Column - ScrollBar.horizontal: ScrollBar { active: true; visible: true; } - } // Tflickable - - TcheckBox { - id: pinBox - hoverEnabled: true - font.pixelSize: fSize - anchors { right: parent.right; bottom: parent.bottom } - checked: chartItem.keepDrawerOpened() - onClicked: { - chartDrawer.closePolicy = checked ? Popup.NoAutoClose : Popup.CloseOnEscape | Popup.CloseOnPressOutside - chartItem.setKeepDrawer(checked) + } - ToolTip { - delay: 500 - timeout: 5000 - visible: pinBox.hovered - contentItem: Text { - text: qsTr("keep opened") - color: activPal.highlightedText - } - enter: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 1 }} - exit: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 0 }} - background: TipRect { shadowRadius: NOO.factor(); color: activPal.highlight } + + background: TipRect { + color: activPal.window + radius: 0 + verticalOffset: 0 + horizontalOffset: pinBox.checked ? 0 : NOO.factor() / 5 } - } - + } diff --git a/src/charts/qml/ChartHelpTip.qml b/src/charts/qml/ChartHelpTip.qml index a9786d35c82a2954822fdf764e9626bfefd0d697..0f77e6f332546d177ed8e3eb8dda6644d76ddcd7 100644 --- a/src/charts/qml/ChartHelpTip.qml +++ b/src/charts/qml/ChartHelpTip.qml @@ -2,40 +2,51 @@ * Copyright (C) 2018-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" +import Nootka 1.0 import QtQuick 2.12 -import Nootka 1.0 -import "../" +TipRect { + id: helpTip + property alias text: txt.text + property color hintColor: GLOB.correctColor -TipRect { - id: helpTip - property alias text: txt.text - property color hintColor: GLOB.correctColor - - shadowRadius: NOO.factor() - width: txt.width + 2 * NOO.factor() - height: txt.height + 2 * NOO.factor() - z: 150 - - border { color: hintColor; width: 1 } - color: Qt.tint(activPal.base, NOO.alpha(hintColor, 50)) - - anchors { centerIn: parent } - - Column { - padding: NOO.factor() - Text { - z: 200 - id: txt - color: activPal.text - textFormat: Text.RichText; horizontalAlignment: Text.AlignHCenter - onLinkActivated: analyzeWindow.openExam() - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - } + shadowRadius: NOO.factor() + width: txt.width + 2 * NOO.factor() + height: txt.height + 2 * NOO.factor() + z: 150 + color: Qt.tint(activPal.base, NOO.alpha(hintColor, 50)) + + border { + color: hintColor + width: 1 + } + + anchors { + centerIn: parent } - } + + Column { + padding: NOO.factor() + + Text { + id: txt + + z: 200 + color: activPal.text + textFormat: Text.RichText + horizontalAlignment: Text.AlignHCenter + onLinkActivated: analyzeWindow.openExam() + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } + + } + + } + } diff --git a/src/charts/qml/ChartTip.qml b/src/charts/qml/ChartTip.qml index d9ed0dcda3cb893eb95f0e2402e6eb697f76d855..1f7d770c05cc9d2da24b53d4ec571807d265bdc9 100644 --- a/src/charts/qml/ChartTip.qml +++ b/src/charts/qml/ChartTip.qml @@ -2,165 +2,259 @@ * Copyright (C) 2018-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - +import "../" +import "../score" import Nootka 1.0 import Nootka.Charts 1.0 +import QtQuick 2.12 import Score 1.0 -import "../score" -import "../" - TipRect { - id: questTip - - property alias tipItem: tipItem - - width: tipItem.width; height: tipItem.height - z: 5000 - x: NOO.bound(parent.height / 12, tipItem.pos.x - chartView.list.contentX, parent.width - width * 1.2) - y: tipItem.pos.y > parent.height / 2 ? tipItem.pos.y - height - parent.height / 14 : tipItem.pos.y + parent.height / 20 - shadowRadius: NOO.factor() * 3; horizontalOffset: NOO.factor() / 3; verticalOffset: horizontalOffset - - visible: scale > 0 - - border { color: tipItem.color; width: NOO.factor() / 7 } - color: Qt.tint(activPal.base, NOO.alpha(tipItem.color, 50)) - radius: NOO.factor() - - scale: tipItem.show ? 1 : 0 - - // overlay area to catch when mouse exits a tip and hide it - MouseArea { - id: overArea - parent: questTip.parent - anchors.fill: parent - z: 4999 - visible: false - hoverEnabled: true - onEntered: { - visible = false - chartItem.tipExited() + // tipItem + + id: questTip + + property alias tipItem: tipItem + + width: tipItem.width + height: tipItem.height + z: 5000 + x: NOO.bound(parent.height / 12, tipItem.pos.x - chartView.list.contentX, parent.width - width * 1.2) + y: tipItem.pos.y > parent.height / 2 ? tipItem.pos.y - height - parent.height / 14 : tipItem.pos.y + parent.height / 20 + shadowRadius: NOO.factor() * 3 + horizontalOffset: NOO.factor() / 3 + verticalOffset: horizontalOffset + visible: scale > 0 + color: Qt.tint(activPal.base, NOO.alpha(tipItem.color, 50)) + radius: NOO.factor() + scale: tipItem.show ? 1 : 0 + + border { + color: tipItem.color + width: NOO.factor() / 7 } - } - - Behavior on scale { NumberAnimation { duration: 200 }} - Behavior on x { NumberAnimation { duration: 200 }} - Behavior on y { NumberAnimation { duration: 200 }} - - TchartTipItem { - id: tipItem - width: (lineCol.visible ? lineCol.width : Math.max(scoreRow.width, headRow.width)) + NOO.factor() - height: (lineCol.visible ? lineCol.height : resultCol.y + resultCol.height) + NOO.factor() - - Row { - id: headRow - y: NOO.factor() / 2 - visible: tipItem.tipType === 0 - spacing: NOO.factor() * 2 - anchors.horizontalCenter: parent.horizontalCenter - Text { - anchors.verticalCenter: parent.verticalCenter - text: tipItem.number + "." - font { bold: true; pixelSize: NOO.factor() * 1.6 } - color: activPal.text - } - Text { - anchors.verticalCenter: parent.verticalCenter - text: tipItem.qaText; horizontalAlignment: Text.AlignHCenter - font { pixelSize: NOO.factor() * 0.8 } - color: activPal.text - } + + // overlay area to catch when mouse exits a tip and hide it + MouseArea { + id: overArea + + parent: questTip.parent + anchors.fill: parent + z: 4999 + visible: false + hoverEnabled: true + onEntered: { + visible = false; + chartItem.tipExited(); + } } - Row { - id: scoreRow - visible: tipItem.tipType === 0 - anchors { horizontalCenter: parent.horizontalCenter; top: headRow.bottom } - Item { - anchors.verticalCenter: parent.verticalCenter - visible: tipItem.leftScoreVisible - height: NOO.factor() * 10; width: NOO.factor() * 10 - Score { - y: tipItem.yScoreLeftOff / 2 - scale: height / firstStaff.linesCount - width: parent.width; height: NOO.factor() * 12 - Component.onCompleted: { - bgRect.destroy() - tipItem.leftScore = scoreObj - } + TchartTipItem { + id: tipItem + + width: (lineCol.visible ? lineCol.width : Math.max(scoreRow.width, headRow.width)) + NOO.factor() + height: (lineCol.visible ? lineCol.height : resultCol.y + resultCol.height) + NOO.factor() + + Row { + id: headRow + + y: NOO.factor() / 2 + visible: tipItem.tipType === 0 + spacing: NOO.factor() * 2 + anchors.horizontalCenter: parent.horizontalCenter + + Text { + anchors.verticalCenter: parent.verticalCenter + text: tipItem.number + "." + color: activPal.text + + font { + bold: true + pixelSize: NOO.factor() * 1.6 + } + + } + + Text { + anchors.verticalCenter: parent.verticalCenter + text: tipItem.qaText + horizontalAlignment: Text.AlignHCenter + color: activPal.text + + font { + pixelSize: NOO.factor() * 0.8 + } + + } + } - } - Text { - visible: !tipItem.leftScoreVisible; anchors.verticalCenter: parent.verticalCenter - text: tipItem.questionText; textFormat: Text.RichText - color: activPal.text - } - Text { // question mark, visible only for single note questions - anchors.verticalCenter: parent.verticalCenter - text: "?"; font { pixelSize: NOO.factor() * 4; family: "Nootka" } - color: GLOB.wrongColor - } - Text { - visible: !tipItem.rightScoreVisible; anchors.verticalCenter: parent.verticalCenter - text: tipItem.answerText; textFormat: Text.RichText - color: activPal.text - } - Item { - height: NOO.factor() * 10; width: NOO.factor() * 10 - anchors.verticalCenter: parent.verticalCenter - visible: tipItem.rightScoreVisible - Score { - y: tipItem.yScoreRightOff / 2 - width: parent.width; height: NOO.factor() * 12 - scale: height / firstStaff.linesCount - Component.onCompleted: { - bgRect.destroy() - tipItem.secondScore = scoreObj - } + + Row { + id: scoreRow + + visible: tipItem.tipType === 0 + + anchors { + horizontalCenter: parent.horizontalCenter + top: headRow.bottom + } + + Item { + anchors.verticalCenter: parent.verticalCenter + visible: tipItem.leftScoreVisible + height: NOO.factor() * 10 + width: NOO.factor() * 10 + + Score { + y: tipItem.yScoreLeftOff / 2 + scale: height / firstStaff.linesCount + width: parent.width + height: NOO.factor() * 12 + Component.onCompleted: { + bgRect.destroy(); + tipItem.leftScore = scoreObj; + } + } + + } + + Text { + visible: !tipItem.leftScoreVisible + anchors.verticalCenter: parent.verticalCenter + text: tipItem.questionText + textFormat: Text.RichText + color: activPal.text + } + // question mark, visible only for single note questions + + Text { + anchors.verticalCenter: parent.verticalCenter + text: "?" + color: GLOB.wrongColor + + font { + pixelSize: NOO.factor() * 4 + family: "Nootka" + } + + } + + Text { + visible: !tipItem.rightScoreVisible + anchors.verticalCenter: parent.verticalCenter + text: tipItem.answerText + textFormat: Text.RichText + color: activPal.text + } + + Item { + height: NOO.factor() * 10 + width: NOO.factor() * 10 + anchors.verticalCenter: parent.verticalCenter + visible: tipItem.rightScoreVisible + + Score { + y: tipItem.yScoreRightOff / 2 + width: parent.width + height: NOO.factor() * 12 + scale: height / firstStaff.linesCount + Component.onCompleted: { + bgRect.destroy(); + tipItem.secondScore = scoreObj; + } + } + + } + // score row + + } + + Column { + id: resultCol + + width: parent.width - NOO.factor() + topPadding: NOO.factor() / 2 + visible: tipItem.tipType === 0 + + anchors { + horizontalCenter: parent.horizontalCenter + top: scoreRow.bottom + } + + Text { + width: parent.width + anchors.horizontalCenter: parent.horizontalCenter + text: tipItem.resultText + textFormat: Text.StyledText + color: tipItem.color + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: tipItem.timeText + textFormat: Text.StyledText + color: activPal.text + horizontalAlignment: Text.AlignHCenter + + font { + pixelSize: NOO.factor() * 0.9 + } + + } + + } + + // line tip column + Column { + id: lineCol + + padding: NOO.factor() / 2 + visible: tipItem.tipType === 1 + + Text { + width: NOO.factor() * 20 + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + textFormat: Text.RichText + text: tipItem.tipText + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + } + } - } - } // score row - - Column { - id: resultCol - anchors { horizontalCenter: parent.horizontalCenter; top: scoreRow.bottom } - width: parent.width - NOO.factor(); topPadding: NOO.factor() / 2 - visible: tipItem.tipType === 0 - Text { - width: parent.width - anchors.horizontalCenter: parent.horizontalCenter - text: tipItem.resultText; textFormat: Text.StyledText - color: tipItem.color; horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - } - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: tipItem.timeText; textFormat: Text.StyledText - font { pixelSize: NOO.factor() * 0.9 } - color: activPal.text; horizontalAlignment: Text.AlignHCenter - } + } - Column { // line tip column - id: lineCol - padding: NOO.factor() / 2 - visible: tipItem.tipType === 1 - Text { - width: NOO.factor() * 20 - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text; textFormat: Text.RichText - text: tipItem.tipText; horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - } + MouseArea { + id: tipArea + + anchors.fill: parent + hoverEnabled: true + onEntered: chartItem.tipEntered() + onExited: overArea.visible = true } - } // tipItem - - MouseArea { - id: tipArea - anchors.fill: parent - hoverEnabled: true - onEntered: chartItem.tipEntered() - onExited: overArea.visible = true - } + + Behavior on scale { + NumberAnimation { + duration: 200 + } + + } + + Behavior on x { + NumberAnimation { + duration: 200 + } + + } + + Behavior on y { + NumberAnimation { + duration: 200 + } + + } + } diff --git a/src/charts/qml/ChartTipMelody.qml b/src/charts/qml/ChartTipMelody.qml index c8a1d1098e8b20beb0830e3cfe8f94257ebe441c..a0d758b42c37f2e130785f76e8807a20af93738e 100644 --- a/src/charts/qml/ChartTipMelody.qml +++ b/src/charts/qml/ChartTipMelody.qml @@ -2,238 +2,336 @@ * Copyright (C) 2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - +import "../" +import "../score" import Nootka.Charts 1.0 +import QtQuick 2.12 import Score 1.0 -import "../score" -import "../" - TipRect { - id: questTip - - property alias tipItem: tipItem - - width: tipItem.width; height: tipItem.height - z: 5000 - x: NOO.bound(parent.height / 12, tipItem.pos.x - chartView.list.contentX, parent.width - width * 1.2) - y: tipItem.pos.y > parent.height / 2 ? tipItem.pos.y - height - parent.height / 14 : tipItem.pos.y + parent.height / 20 - shadowRadius: NOO.factor() * 3; horizontalOffset: NOO.factor() / 3; verticalOffset: horizontalOffset - - visible: scale > 0 - - border { color: tipItem.color; width: NOO.factor() / 7 } - color: Qt.tint(activPal.base, NOO.alpha(tipItem.color, 50)) - radius: NOO.factor() - - scale: tipItem.show ? 1 : 0 - - // overlay area to catch when mouse exits a tip and hide it - MouseArea { - id: overArea - parent: questTip.parent - anchors.fill: parent - z: 4999 - visible: false - hoverEnabled: true - onEntered: { - visible = false - chartItem.tipExited() - } - } + id: questTip - Behavior on scale { NumberAnimation { duration: 200 }} - Behavior on x { NumberAnimation { duration: 200 }} - Behavior on y { NumberAnimation { duration: 200 }} + property alias tipItem: tipItem - TchartTipItem { - id: tipItem + width: tipItem.width + height: tipItem.height + z: 5000 + x: NOO.bound(parent.height / 12, tipItem.pos.x - chartView.list.contentX, parent.width - width * 1.2) + y: tipItem.pos.y > parent.height / 2 ? tipItem.pos.y - height - parent.height / 14 : tipItem.pos.y + parent.height / 20 + shadowRadius: NOO.factor() * 3 + horizontalOffset: NOO.factor() / 3 + verticalOffset: horizontalOffset + visible: scale > 0 + color: Qt.tint(activPal.base, NOO.alpha(tipItem.color, 50)) + radius: NOO.factor() + scale: tipItem.show ? 1 : 0 - property bool prevShown: false /**< @p TRUE when user displayed entire melody */ + border { + color: tipItem.color + width: NOO.factor() / 7 + } - width: (lineCol.visible ? lineCol.width : Math.max(scoreRow.width, headRow.width)) + NOO.factor() - height: tipCol.height + NOO.factor() + // overlay area to catch when mouse exits a tip and hide it + MouseArea { + id: overArea - onQuestionWasSet: { - attemptSpin.value = 0 - prevShown = false + parent: questTip.parent + anchors.fill: parent + z: 4999 + visible: false + hoverEnabled: true + onEntered: { + visible = false; + chartItem.tipExited(); + } } - Column { - id: tipCol - spacing: NOO.factor() / 2 - - Row { - id: headRow - visible: tipItem.tipType === 0 - spacing: NOO.factor() * 2 - anchors.horizontalCenter: parent.horizontalCenter - Text { - anchors.verticalCenter: parent.verticalCenter - text: tipItem.number + "." - font { bold: true; pixelSize: NOO.factor() * 1.6 } - color: activPal.text - } - Text { - anchors.verticalCenter: parent.verticalCenter - text: tipItem.qaText; horizontalAlignment: Text.AlignHCenter - font { pixelSize: NOO.factor() * 0.8 } - color: activPal.text - } - } - - Rectangle { - id: scoreRow - visible: tipItem.leftScoreVisible && tipItem.tipType === 0 - x: NOO.factor() / 2 - color: activPal.base - height: tipItem.leftScoreHeight - NOO.factor(); width: NOO.factor() * 40 - clip: true - Score { - id: score - y: tipItem.yScoreLeftOff - width: parent.width; height: NOO.factor() * 15 - Component.onCompleted: { - bgRect.destroy() - tipItem.leftScore = scoreObj - } - } - Rectangle { - height: parent.height; width: parent.height - rotation: -90 - anchors.right: parent.right - visible: tipItem.moreMelody && !tipItem.prevShown - gradient: Gradient { - GradientStop { position: 0.0; color: "transparent" } - GradientStop { position: 0.5; color: activPal.base } - } - RectButton { - anchors.horizontalCenter: parent.horizontalCenter; y: parent.height * 0.66 - height: parent.height / 3 - rotation: 90 - font { family: "Nootka"; pixelSize: parent.height / 3 } - text: "\u0191" - textColor: activPal.text - // onClicked performed by mouse area - } - } - } - - TspinBox { - id: attemptSpin - anchors.horizontalCenter: parent.horizontalCenter - visible: tipItem.isMelody && tipItem.tipType === 0 - width: NOO.factor() * 15 - font.pixelSize: NOO.factor() * 0.8 - from: 0; to: tipItem.attempts - textFromValue: function(value) { - return NOO.TR("Texam", "attempt") + " " + value + " " + qsTranslate("ChartTip", "of", "It will give text: 'Attempt x of y'") + " " + to - } - function pressed(m) { - if (m.x > width / 2) - up.pressed = true - else - down.pressed = true - } - function released() { - if (down.pressed || up.pressed) { - var prevV = value - if (up.pressed) - increase() - else - decrease() - if (prevV !== value) - tipItem.setAttemptNr(value) - } - up.pressed = false - down.pressed = false + TchartTipItem { + id: tipItem + + property bool prevShown: false //*< @p TRUE when user displayed entire melody + + width: (lineCol.visible ? lineCol.width : Math.max(scoreRow.width, headRow.width)) + NOO.factor() + height: tipCol.height + NOO.factor() + onQuestionWasSet: { + attemptSpin.value = 0; + prevShown = false; } - } - - Column { - id: resultCol - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - NOO.factor() - visible: tipItem.tipType === 0 - Text { - width: parent.width; visible: text !== "" - anchors.horizontalCenter: parent.horizontalCenter - text: tipItem.attemptDetails(attemptSpin.value); textFormat: Text.StyledText - color: activPal.text; horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap; font.pixelSize: NOO.factor() * 0.9 + + Column { + id: tipCol + + spacing: NOO.factor() / 2 + + Row { + id: headRow + + visible: tipItem.tipType === 0 + spacing: NOO.factor() * 2 + anchors.horizontalCenter: parent.horizontalCenter + + Text { + anchors.verticalCenter: parent.verticalCenter + text: tipItem.number + "." + color: activPal.text + + font { + bold: true + pixelSize: NOO.factor() * 1.6 + } + + } + + Text { + anchors.verticalCenter: parent.verticalCenter + text: tipItem.qaText + horizontalAlignment: Text.AlignHCenter + color: activPal.text + + font { + pixelSize: NOO.factor() * 0.8 + } + + } + + } + + Rectangle { + id: scoreRow + + visible: tipItem.leftScoreVisible && tipItem.tipType === 0 + x: NOO.factor() / 2 + color: activPal.base + height: tipItem.leftScoreHeight - NOO.factor() + width: NOO.factor() * 40 + clip: true + + Score { + id: score + + y: tipItem.yScoreLeftOff + width: parent.width + height: NOO.factor() * 15 + Component.onCompleted: { + bgRect.destroy(); + tipItem.leftScore = scoreObj; + } + } + + Rectangle { + height: parent.height + width: parent.height + rotation: -90 + anchors.right: parent.right + visible: tipItem.moreMelody && !tipItem.prevShown + + RectButton { + // onClicked performed by mouse area + + anchors.horizontalCenter: parent.horizontalCenter + y: parent.height * 0.66 + height: parent.height / 3 + rotation: 90 + text: "\u0191" + textColor: activPal.text + + font { + family: "Nootka" + pixelSize: parent.height / 3 + } + + } + + gradient: Gradient { + GradientStop { + position: 0 + color: "transparent" + } + + GradientStop { + position: 0.5 + color: activPal.base + } + + } + + } + + } + + TspinBox { + id: attemptSpin + + function pressed(m) { + if (m.x > width / 2) + up.pressed = true; + else + down.pressed = true; + } + + function released() { + if (down.pressed || up.pressed) { + var prevV = value; + if (up.pressed) + increase(); + else + decrease(); + if (prevV !== value) + tipItem.setAttemptNr(value); + + } + up.pressed = false; + down.pressed = false; + } + + anchors.horizontalCenter: parent.horizontalCenter + visible: tipItem.isMelody && tipItem.tipType === 0 + width: NOO.factor() * 15 + font.pixelSize: NOO.factor() * 0.8 + from: 0 + to: tipItem.attempts + textFromValue: function(value) { + return NOO.TR("Texam", "attempt") + " " + value + " " + qsTranslate("ChartTip", "of", "It will give text: 'Attempt x of y'") + " " + to; + } + } + + Column { + id: resultCol + + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - NOO.factor() + visible: tipItem.tipType === 0 + + Text { + width: parent.width + visible: text !== "" + anchors.horizontalCenter: parent.horizontalCenter + text: tipItem.attemptDetails(attemptSpin.value) + textFormat: Text.StyledText + color: activPal.text + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + font.pixelSize: NOO.factor() * 0.9 + } + + Text { + width: parent.width // visible: text !== "" + anchors.horizontalCenter: parent.horizontalCenter + text: tipItem.attemptResult(attemptSpin.value) + textFormat: Text.StyledText + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + font.pixelSize: NOO.factor() * 0.9 + } + + Text { + width: parent.width + visible: text !== "" + anchors.horizontalCenter: parent.horizontalCenter + text: attemptSpin.value === 0 ? tipItem.resultText : "" + textFormat: Text.StyledText + color: tipItem.color + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: tipItem.timeText + textFormat: Text.StyledText + color: activPal.text + horizontalAlignment: Text.AlignHCenter + + font { + pixelSize: NOO.factor() * 0.9 + } + + } + + } + + // line tip column + Column { + id: lineCol + + padding: NOO.factor() + visible: tipItem.tipType === 1 + + Text { + width: NOO.factor() * 20 + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + textFormat: Text.RichText + text: tipItem.tipText + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + } + + } + } - Text { - width: parent.width;// visible: text !== "" - anchors.horizontalCenter: parent.horizontalCenter - text: tipItem.attemptResult(attemptSpin.value); textFormat: Text.StyledText - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap; font.pixelSize: NOO.factor() * 0.9 + // tipItem + + } + + MouseArea { + id: tipArea + + property real startPosY: 0 + property bool overScore: false + + anchors.fill: parent + hoverEnabled: true + onEntered: chartItem.tipEntered() + onExited: overArea.visible = true + onPressed: { + startPosY = mouseY; + if (tipCol.childAt(mouse.x, mouse.y) !== scoreRow) + attemptSpin.pressed(mapToItem(attemptSpin, mouse.x, mouse.y)); + else if (tipItem.moreMelody && tipItem.prevShown) + overScore = true; } - Text { - width: parent.width; visible: text !== "" - anchors.horizontalCenter: parent.horizontalCenter - text: attemptSpin.value === 0 ? tipItem.resultText : ""; textFormat: Text.StyledText - color: tipItem.color; horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap + onPositionChanged: { + if (overScore) { + score.contentY -= (mouseY - startPosY); + startPosY = mouseY; + } } - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: tipItem.timeText; textFormat: Text.StyledText - font { pixelSize: NOO.factor() * 0.9 } - color: activPal.text; horizontalAlignment: Text.AlignHCenter + onReleased: { + if (tipCol.childAt(mouse.x, mouse.y) === scoreRow) { + if (tipItem.moreMelody && !tipItem.prevShown) { + tipItem.showMelodyPreview(); + tipItem.prevShown = true; + } + } else { + attemptSpin.released(); + } + if (overScore) { + overScore = false; + score.returnToBounds(); + } } - } - - Column { // line tip column - id: lineCol - padding: NOO.factor() - visible: tipItem.tipType === 1 - Text { - width: NOO.factor() * 20 - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text; textFormat: Text.RichText - text: tipItem.tipText; horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap + } + + Behavior on scale { + NumberAnimation { + duration: 200 } - } } - } // tipItem - - MouseArea { - id: tipArea - anchors.fill: parent - hoverEnabled: true - onEntered: chartItem.tipEntered() - onExited: overArea.visible = true - property real startPosY: 0 - property bool overScore: false - onPressed: { - startPosY = mouseY - if (tipCol.childAt(mouse.x, mouse.y) !== scoreRow) - attemptSpin.pressed(mapToItem(attemptSpin, mouse.x, mouse.y)) - else if (tipItem.moreMelody && tipItem.prevShown) - overScore = true - } - onPositionChanged: { - if (overScore) { - score.contentY -= (mouseY - startPosY) - startPosY = mouseY - } + + Behavior on x { + NumberAnimation { + duration: 200 + } + } - onReleased: { - if (tipCol.childAt(mouse.x, mouse.y) === scoreRow) { - if (tipItem.moreMelody && !tipItem.prevShown) { - tipItem.showMelodyPreview() - tipItem.prevShown = true + + Behavior on y { + NumberAnimation { + duration: 200 } - } else - attemptSpin.released() - if (overScore) { - overScore = false - score.returnToBounds() - } + } - } + } diff --git a/src/charts/qml/ChartToolButton.qml b/src/charts/qml/ChartToolButton.qml index 9b40252e0566c8bf32c591e76866ee036fbd4da8..7f06ab22ce54189531bace7ffe265c4a526ae3f8 100644 --- a/src/charts/qml/ChartToolButton.qml +++ b/src/charts/qml/ChartToolButton.qml @@ -2,57 +2,92 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Window 2.12 -import Nootka 1.0 -import "../" +ToolButton { + id: root + property alias pixmap: pix.source + property real factor: analyzeWindow.height / 150 + property Taction taction -ToolButton { - id: root - - hoverEnabled: true - - width: pix.width + (NOO.isAndroid() ? 4 : factor * 2) - height: pix.height + Screen.pixelDensity * 2 - enabled: (taction && taction.enabled) || !taction - - property alias pixmap: pix.source - property real factor: analyzeWindow.height / 150 - property Taction taction - - background: Item {} - - onClicked: { - if (taction) - taction.trigger() - focus = false - } - - Image { - id: pix - mipmap: true - anchors.centerIn: parent - source: taction ? taction.icon : "" - height: factor * 10; width: height * (sourceSize.width / sourceSize.height) - transformOrigin: Image.Center - scale: !enabled || pressed ? 0.6 : (hovered ? 1.1 : 0.8) - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - } - - ToolTip { - id: toolTip - delay: 750 - timeout: 5000 - visible: hovered && contentItem.text !== "" - contentItem: Text { - text: taction ? taction.text : "" - color: activPal.highlightedText + hoverEnabled: true + width: pix.width + (NOO.isAndroid() ? 4 : factor * 2) + height: pix.height + Screen.pixelDensity * 2 + enabled: (taction && taction.enabled) || !taction + onClicked: { + if (taction) + taction.trigger(); + + focus = false; } - enter: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 1 }} - exit: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 0 }} - background: TipRect { shadowRadius: NOO.factor(); color: activPal.highlight } - } + + Image { + id: pix + + mipmap: true + anchors.centerIn: parent + source: taction ? taction.icon : "" + height: factor * 10 + width: height * (sourceSize.width / sourceSize.height) + transformOrigin: Image.Center + scale: !enabled || pressed ? 0.6 : (hovered ? 1.1 : 0.8) + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + } + + ToolTip { + id: toolTip + + delay: 750 + timeout: 5000 + visible: hovered && contentItem.text !== "" + + contentItem: Text { + text: taction ? taction.text : "" + color: activPal.highlightedText + } + + enter: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 1 + } + + } + + exit: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 0 + } + + } + + background: TipRect { + shadowRadius: NOO.factor() + color: activPal.highlight + } + + } + + background: Item { + } + } diff --git a/src/charts/qml/ChartView.qml b/src/charts/qml/ChartView.qml index de67e86313a0e18f4bfb2749b012fb8c51de4ae5..f27285080b1d0a8cd79397f6453c36b68d489ea1 100644 --- a/src/charts/qml/ChartView.qml +++ b/src/charts/qml/ChartView.qml @@ -2,156 +2,234 @@ * Copyright (C) 2019-2020 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka import QtQuick 2.12 import QtQuick.Controls 2.12 - Flickable { - id: chartView - - property alias list: list - property real sc: 1.0 - property real lThick: (height / 150.0) * sc - property real maxDataHeight: chartView.height * 0.7333333333333333 *sc - - boundsBehavior: Flickable.StopAtBounds - clip: true - contentHeight: height * sc - - Timer { id: zoomTimer; interval: 100 } - MouseArea { - anchors.fill: parent - enabled: list.count > 0 - onWheel: { - if (wheel.modifiers & Qt.ControlModifier) { - if (wheel.angleDelta.y > 0) { - if (!zoomTimer.running) { - sc = Math.min(2.0, sc * 1.125) - zoomTimer.running = true - } - } else if (wheel.angleDelta.y < 0) { - if (!zoomTimer.running) { - sc = Math.max(0.5, sc * 0.888889) - zoomTimer.running = true - } - } - } else - wheel.accepted = false - } - } - - Repeater { // Y grid lines - model: chartItem.yAxisGridModel.length - Rectangle { - visible: list.count > 0; z: 0 - y: contentHeight * 0.1 + maxDataHeight - (chartItem.yAxisGridModel[index] / chartItem.maxYValue()) * maxDataHeight - color: NOO.alpha(activPal.text, 100) - width: Math.min(parent.width - list.height / 12, list.contentWidth); height: lThick / 3 - x: list.height / 12 - } - } - - Component { - id: lineComp - LinearDelegate { - chart: chartItem - chartNr: modelIndex - height: chartView.height * sc; width: height / 6 - } - } - - Component { - id: barComp - BarDelegate { - chart: chartItem - groupNr: modelIndex - height: chartView.height * sc; width: height / 6 - } - } + id: chartView - ListView { - id: list - z: 1 - width: parent.width; height: chartView.height * sc + property alias list: list + property real sc: 1 + property real lThick: (height / 150) * sc + property real maxDataHeight: chartView.height * 0.733333 * sc - orientation: ListView.Horizontal boundsBehavior: Flickable.StopAtBounds + clip: true + contentHeight: height * sc - model: chartItem.chartModel + Timer { + id: zoomTimer - delegate: Component { - Loader { - property int modelIndex: index - z: 2000 - modelIndex; // for proper overlapping keep 'z' stack in reverse order as delegates are created - sourceComponent: chartItem.chartType === 0 ? lineComp : barComp - } + interval: 100 } - header: Item { // fake, just to force space on the chart left - visible: list.count > 0 - height: list.height; width: height / 12 + MouseArea { + anchors.fill: parent + enabled: list.count > 0 + onWheel: wheel => { + if (wheel.modifiers & Qt.ControlModifier) { + if (wheel.angleDelta.y > 0) { + if (!zoomTimer.running) { + sc = Math.min(2, sc * 1.125); + zoomTimer.running = true; + } + } else if (wheel.angleDelta.y < 0) { + if (!zoomTimer.running) { + sc = Math.max(0.5, sc * 0.888889); + zoomTimer.running = true; + } + } + } else { + wheel.accepted = false; + } + } } - footer: Item { - visible: list.count > 0 - height: list.height; width: height / 6 - Rectangle { - color: activPal.text - y: parent.height - parent.width + lThick / 2 - width: parent.width / 1.3; height: lThick - Repeater { // X arrow - model: 2 - Rectangle { - x: parent.width - color: activPal.text; radius: width / 2 - height: lThick; width: lThick * 5 - rotation: index === 0 ? 155 : -155; transformOrigin: Item.Left - } + // Y grid lines + Repeater { + model: chartItem.yAxisGridModel.length + + Rectangle { + visible: list.count > 0 + z: 0 + y: contentHeight * 0.1 + maxDataHeight - (chartItem.yAxisGridModel[index] / chartItem.maxYValue()) * maxDataHeight + color: NOO.alpha(activPal.text, 100) + width: Math.min(parent.width - list.height / 12, list.contentWidth) + height: lThick / 3 + x: list.height / 12 } - } + } - Rectangle { // Y axis (over that fake header) - visible: list.count > 0 - color: NOO.alpha(activPal.base, 200) - height: list.height; width: height / 12 - Rectangle { // Y axis line - color: activPal.text - x: parent.width; y: parent.height * 0.01 + lThick / 2 - width: lThick; height: parent.height * 0.8233333333333333 - Repeater { // Y arrow - model: 2 - Rectangle { - color: activPal.text; radius: width / 2 - width: lThick; height: lThick * 5 - rotation: index === 0 ? 25 : -25; transformOrigin: Item.Top - } + Component { + id: lineComp + + LinearDelegate { + chart: chartItem + chartNr: modelIndex + height: chartView.height * sc + width: height / 6 } - Text { // Y label - font { pixelSize: lThick * 5; bold: true } - y: (parent.height - height) / 2; x: -width / 2 - height - color: activPal.text - text: chartItem.yAxisLabel - rotation: -90 + + } + + Component { + id: barComp + + BarDelegate { + chart: chartItem + groupNr: modelIndex + height: chartView.height * sc + width: height / 6 } - } - Repeater { // ticks and Y values (text) - model: chartItem.yAxisGridModel.length + + } + + ListView { + id: list + + z: 1 + width: parent.width + height: chartView.height * sc + orientation: ListView.Horizontal + boundsBehavior: Flickable.StopAtBounds + model: chartItem.chartModel + + // Y axis (over that fake header) Rectangle { - y: contentHeight * 0.1 + maxDataHeight - (chartItem.yAxisGridModel[index] / chartItem.maxYValue()) * maxDataHeight - lThick / 4 - color: activPal.text - width: lThick * 1.5; height: lThick - x: parent.width - width - Text { - color: activPal.text; text: index < chartItem.yAxisGridModel.length ? chartItem.yAxisTickText(index) : "" - font { pixelSize: lThick * 3.5 } - y: -height + lThick / 2; x: lThick * 3 - } + visible: list.count > 0 + color: NOO.alpha(activPal.base, 200) + height: list.height + width: height / 12 + + // Y axis line + Rectangle { + color: activPal.text + x: parent.width + y: parent.height * 0.01 + lThick / 2 + width: lThick + height: parent.height * 0.823333 + + // Y arrow + Repeater { + model: 2 + + Rectangle { + color: activPal.text + radius: width / 2 + width: lThick + height: lThick * 5 + rotation: index === 0 ? 25 : -25 + transformOrigin: Item.Top + } + + } + + // Y label + Text { + y: (parent.height - height) / 2 + x: -width / 2 - height + color: activPal.text + text: chartItem.yAxisLabel + rotation: -90 + + font { + pixelSize: lThick * 5 + bold: true + } + + } + + } + + // ticks and Y values (text) + Repeater { + model: chartItem.yAxisGridModel.length + + Rectangle { + y: contentHeight * 0.1 + maxDataHeight - (chartItem.yAxisGridModel[index] / chartItem.maxYValue()) * maxDataHeight - lThick / 4 + color: activPal.text + width: lThick * 1.5 + height: lThick + x: parent.width - width + + Text { + color: activPal.text + text: index < chartItem.yAxisGridModel.length ? chartItem.yAxisTickText(index) : "" + y: -height + lThick / 2 + x: lThick * 3 + + font { + pixelSize: lThick * 3.5 + } + + } + + } + + } + + } + + delegate: Component { + Loader { + property int modelIndex: index + + z: 2000 - modelIndex // for proper overlapping keep 'z' stack in reverse order as delegates are created + sourceComponent: chartItem.chartType === 0 ? lineComp : barComp + } + } - } + + // fake, just to force space on the chart left + header: Item { + visible: list.count > 0 + height: list.height + width: height / 12 + } + + footer: Item { + visible: list.count > 0 + height: list.height + width: height / 6 + + Rectangle { + color: activPal.text + y: parent.height - parent.width + lThick / 2 + width: parent.width / 1.3 + height: lThick + + // X arrow + Repeater { + model: 2 + + Rectangle { + x: parent.width + color: activPal.text + radius: width / 2 + height: lThick + width: lThick * 5 + rotation: index === 0 ? 155 : -155 + transformOrigin: Item.Left + } + + } + + } + + } + + ScrollBar.horizontal: ScrollBar { + active: true + visible: true + } + + } + + ScrollBar.vertical: ScrollBar { + active: true + visible: true } - ScrollBar.horizontal: ScrollBar { active: true; visible: true } - } - ScrollBar.vertical: ScrollBar { active: true; visible: true } }