diff --git a/src/main.cpp b/src/main.cpp index c01efcf5b5c50e2cd81b9600334247840a1ed8b5..7a7b3672b15561d4f60e3643ebf6779f380ffc2b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -79,10 +79,6 @@ int main(int argc, char *argv[]) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif - // It mutes QML warnings about connections syntax introduced in Qt 5.15 - // TODO when Qt version requirements will rise to 5.15 or above, change syntax and remove that - QLoggingCategory::setFilterRules(QStringLiteral("qt.qml.connections=false")); - #if defined(Q_OS_ANDROID) qputenv("QT_ANDROID_VOLUME_KEYS", "1"); // Handle volume keys by Qt, lock native Android behavior diff --git a/src/qml/+android/FlyItem.qml b/src/qml/+android/FlyItem.qml index c84768ee3a806b52898bdd1d8506c05131c96824..77d0bd3855f6011975a83ce68d4a0aef857b33fa 100644 --- a/src/qml/+android/FlyItem.qml +++ b/src/qml/+android/FlyItem.qml @@ -2,78 +2,117 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 +AbstractButton { + id: flyItem + property Taction taction: null + property bool shaked: false + property int index: 0 + property bool canShow: taction && taction.enabled + + x: canShow && (showFlys || shaked) ? flyX(index) : -width + y: canShow && (showFlys || shaked) ? flyY(index) : -height + scale: canShow && (showFlys || shaked) ? 0.99 : 0.01 + width: NOO.fingerPixels() * 1.5 + (txt.visible ? txt.width : 0) + height: NOO.fingerPixels() * 1.5 + onClicked: { + taction.trigger(); + shakeTimer.stop(); + shaked = false; + } + + Connections { + target: taction + onShakeButton: { + shaked = true; + shakeTimer.start(); + } + } + + Timer { + id: shakeTimer + + interval: 2500 + onTriggered: { + if (pressed) + shakeTimer.start(); + else + shaked = false; + } + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + Behavior on x { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } -AbstractButton { - id: flyItem - property Taction taction: null - property bool shaked: false - property int index: 0 - property bool canShow: taction && taction.enabled - - x: canShow && (showFlys || shaked) ? flyX(index) : -width - y: canShow && (showFlys || shaked) ? flyY(index) : -height - scale: canShow && (showFlys || shaked) ? 0.99 : 0.01 - width: NOO.fingerPixels() * 1.5 + (txt.visible ? txt.width : 0) - height: NOO.fingerPixels() * 1.5 - - onClicked: { - taction.trigger() - shakeTimer.stop() - shaked = false - } - - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - Behavior on x { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - Behavior on y { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - - background: TipRect { - radius: height / 2 - color: Qt.tint(activPal.base, NOO.alpha(taction ? taction.bgColor : activPal.base, currentFly === flyItem || pressed ? 200 : 50)) - border { width: 2; color: taction ? taction.bgColor : "transparent" } - } - - contentItem: Item { - Image { - id: img - x: (NOO.fingerPixels() * 1.5 - width) / 2 - source: taction ? taction.icon : "" - height: parent.height * 0.7; width: height * (sourceSize.width / sourceSize.height) - anchors.verticalCenter: parent.verticalCenter } - Text { - id: txt - visible: forceText || (showText && taction && currentFly === flyItem) - anchors { verticalCenter: parent.verticalCenter; left: img.right } - padding: NOO.factor() / 3 - horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter - minimumPixelSize: 8 - fontSizeMode: Text.HorizontalFit - color: activPal.text - text: taction ? taction.text : "" + + Behavior on y { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + } - } - Connections { - target: taction - onShakeButton: { - shaked = true - shakeTimer.start() + background: TipRect { + radius: height / 2 + color: Qt.tint(activPal.base, NOO.alpha(taction ? taction.bgColor : activPal.base, currentFly === flyItem || pressed ? 200 : 50)) + + border { + width: 2 + color: taction ? taction.bgColor : "transparent" + } + } - } - - Timer { - id: shakeTimer - interval: 2500 - onTriggered: { - if (pressed) - shakeTimer.start() - else - shaked = false + + contentItem: Item { + Image { + id: img + + x: (NOO.fingerPixels() * 1.5 - width) / 2 + source: taction ? taction.icon : "" + height: parent.height * 0.7 + width: height * (sourceSize.width / sourceSize.height) + anchors.verticalCenter: parent.verticalCenter + } + + Text { + id: txt + + visible: forceText || (showText && taction && currentFly === flyItem) + padding: NOO.factor() / 3 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + minimumPixelSize: 8 + fontSizeMode: Text.HorizontalFit + color: activPal.text + text: taction ? taction.text : "" + + anchors { + verticalCenter: parent.verticalCenter + left: img.right + } + + } + } - } + } diff --git a/src/qml/+android/MainMenuMobile.qml b/src/qml/+android/MainMenuMobile.qml index a6884196b5a70a1145bc44cf2e811b56b5bfe696..9bd025e32fa36e74df40ece96ec30149e8d78070 100644 --- a/src/qml/+android/MainMenuMobile.qml +++ b/src/qml/+android/MainMenuMobile.qml @@ -2,294 +2,474 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 +import Qt5Compat.GraphicalEffects import QtQuick 2.12 import QtQuick.Controls 2.12 -import Qt5Compat.GraphicalEffects - -import Nootka 1.0 import "sound" - TmobileMenu { - id: root + id: root + + property Item toolBar: null // fake, for main window information + property alias drawer: mainDrawer + // private + property var scoreMenu: null + property var tempoMenu: null + property var clearPopup: null - property Item toolBar: null // fake, for main window information - property alias drawer: mainDrawer + function open() { + if (!scoreMenu) { + var c = Qt.createComponent("qrc:/ScoreMenuContent.qml"); + scoreMenu = c.createObject(nootkaWindow.contentItem.parent, { + "width": NOO.factor() * 15, + "z": -1 + }); + } + scoreMenu.open(); + } - // private - property var scoreMenu: null - property var tempoMenu: null - property var clearPopup: null + onClicked: mainDrawer.open() + parent: nootkaWindow.contentItem + z: 550 + width: fingerPixels() + height: fingerPixels() * 1.3 + onWantClearScore: { + if (!clearPopup) + clearPopup = clearComp.createObject(nootkaWindow.contentItem); - function open() { - if (!scoreMenu) { - var c = Qt.createComponent("qrc:/ScoreMenuContent.qml") - scoreMenu = c.createObject(nootkaWindow.contentItem.parent, { "width": NOO.factor() * 15, "z": -1 }) + clearPopup.open(); } - scoreMenu.open() - } - - onClicked: mainDrawer.open() - - parent: nootkaWindow.contentItem - z: 550 - width: fingerPixels() - height: fingerPixels() * 1.3 - - Rectangle { - id: bg - width: fingerPixels() * 0.7; height: fingerPixels() * 1.3; x: fingerPixels() / 10; y: fingerPixels() / 10; - color: NOO.alpha(activPal.highlight, pressed ? 255 : 25) - radius: fingerPixels() / 10 - Column { - width: parent.width - spacing: bg.width / 4 - topPadding: spacing - Rectangle { - width: bg.width / 4; height: width; radius: width / 2 - anchors.horizontalCenter: parent.horizontalCenter - color: SOUND.playing ? "lime" : "black" - } - Rectangle { - width: bg.width / 4; height: width; radius: width / 2 - anchors.horizontalCenter: parent.horizontalCenter - color: "black" - } - Rectangle { - id: pitchDot - width: bg.width / 4; height: width; radius: width / 2 - anchors.horizontalCenter: parent.horizontalCenter - color: SOUND.listening ? "mediumturquoise" : "black" - } + onFlyClicked: { + if (currentFly) + currentFly.taction.trigger(); + } - } - - Taction { - id: tunerAct - text: NOO.TR("TunerDialog", "Nooter - Nootka tuner").replace("-", "<br><font size=\"1\">") + "</font>" - icon: "fork" - onTriggered: { - nootkaWindow.showDialog(Nootka.Tuner) - SOUND.startListen() + + Rectangle { + id: bg + + width: fingerPixels() * 0.7 + height: fingerPixels() * 1.3 + x: fingerPixels() / 10 + y: fingerPixels() / 10 + color: NOO.alpha(activPal.highlight, pressed ? 255 : 25) + radius: fingerPixels() / 10 + + Column { + width: parent.width + spacing: bg.width / 4 + topPadding: spacing + + Rectangle { + width: bg.width / 4 + height: width + radius: width / 2 + anchors.horizontalCenter: parent.horizontalCenter + color: SOUND.playing ? "lime" : "black" + } + + Rectangle { + width: bg.width / 4 + height: width + radius: width / 2 + anchors.horizontalCenter: parent.horizontalCenter + color: "black" + } + + Rectangle { + id: pitchDot + + width: bg.width / 4 + height: width + radius: width / 2 + anchors.horizontalCenter: parent.horizontalCenter + color: SOUND.listening ? "mediumturquoise" : "black" + } + + } + } - } - - Connections { - target: tempoAct - onTriggered: { - if (!tempoMenu) - tempoMenu = Qt.createComponent("qrc:/sound/TempoMenu.qml").createObject(nootkaWindow.contentItem) - tempoMenu.open() + + Taction { + id: tunerAct + + text: NOO.TR("TunerDialog", "Nooter - Nootka tuner").replace("-", "<br><font size=\"1\">") + "</font>" + icon: "fork" + onTriggered: { + nootkaWindow.showDialog(Nootka.Tuner); + SOUND.startListen(); + } } - } - - Drawer { - id: mainDrawer - property NootkaLabel label: null - width: NOO.factor() * 20; height: nootkaWindow.height - - onVisibleChanged: { - if (visible) { - if (!drawerLoad.active) - drawerLoad.active = true - label.bgColor = NOO.randomColor() - SOUND.stopListen() - } else { - if (!dialogLoader || !dialogLoader.visible) - SOUND.startListen() - } + + Connections { + target: tempoAct + onTriggered: { + if (!tempoMenu) + tempoMenu = Qt.createComponent("qrc:/sound/TempoMenu.qml").createObject(nootkaWindow.contentItem); + + tempoMenu.open(); + } } - Loader { - id: drawerLoad - active: false - anchors.fill: parent - sourceComponent: Component { - Flickable { - anchors.fill: parent - clip: true - contentHeight: drawerColumn.height - Column { - id: drawerColumn - property var drawer: mainDrawer - width: parent.width - spacing: fingerPixels() / 8 - NootkaLabel { - id: nooLabel - height: NOO.factor() * 7.91015625 // (logo ratio) 0.3955078125 * 20 - enabled: !GLOB.isExam - clip: true - onClicked: { - mainDrawer.close() - NOO.aboutAct.trigger() - } - Component.onCompleted: mainDrawer.label = this - - property int currentItem: 0 - ListModel { - id: paneModel - ListElement { txt: "About"; img: "about" } - ListElement { txt: "Help"; img: "help" } - ListElement { txt: "Authors"; img: "author" } - ListElement { txt: "License"; img: "license" } - ListElement { txt: "Support"; img: "support" } - ListElement { txt: "Changes"; img: "changes" } - } - - Rectangle { - id: item - width: parent.height / 2; height: width * 1.4 - x: parent.width - width - NOO.factor() / 4; y: -height - radius: width / 8 - color: Qt.rgba(0, 0, 0, 0.8) - Image { - id: paneImg - source: NOO.pix("pane/" + paneModel.get(nooLabel.currentItem).img) - height: parent.width; width: height * (sourceSize.width / sourceSize.height) - visible: false - } - Colorize { - anchors.fill: paneImg - source: paneImg - hue: 0; lightness: 0.5; saturation: 0 - } - Text { - anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom } - color: nooLabel.bgColor - text: NOO.TR(nooLabel.currentItem === 1 ? "QShortcut" : "TaboutNootka", paneModel.get(nooLabel.currentItem).txt) - width: parent.width; horizontalAlignment: Text.AlignHCenter - fontSizeMode: Text.Fit; minimumPixelSize: NOO.factor() / 2 - } - SequentialAnimation { - loops: paneModel.count - running: true - PauseAnimation { duration: 500 } - PropertyAnimation { - target: item; property: "y" - duration: 250 - to: (item.parent.height - item.height) / 2 - } - PauseAnimation { duration: 1500 } - PropertyAnimation { - target: item; property: "y" - duration: 500 - to: item.parent.height + item.height - } - ScriptAction { - script: { - item.y = -item.height - if (nooLabel.currentItem < paneModel.count - 1) - nooLabel.currentItem++ - } - } - } - } + Drawer { + id: mainDrawer + + property NootkaLabel label: null + + width: NOO.factor() * 20 + height: nootkaWindow.height + onVisibleChanged: { + if (visible) { + if (!drawerLoad.active) + drawerLoad.active = true; + + label.bgColor = NOO.randomColor(); + SOUND.stopListen(); + } else { + if (!dialogLoader || !dialogLoader.visible) + SOUND.startListen(); + } - Repeater { - model: examActions - MenuButton { - action: modelData - visible: action && action.enabled - Rectangle { - width: NOO.factor() * 3; height: parent.height - z: -1 - color: action ? NOO.alpha(action.bgColor, 50) : "transparent" + } + + Loader { + id: drawerLoad + + active: false + anchors.fill: parent + + sourceComponent: Component { + Flickable { + anchors.fill: parent + clip: true + contentHeight: drawerColumn.height + + Column { + id: drawerColumn + + property var drawer: mainDrawer + + width: parent.width + spacing: fingerPixels() / 8 + + NootkaLabel { + id: nooLabel + + property int currentItem: 0 + + height: NOO.factor() * 7.91016 // (logo ratio) 0.3955078125 * 20 + enabled: !GLOB.isExam + clip: true + onClicked: { + mainDrawer.close(); + NOO.aboutAct.trigger(); + } + Component.onCompleted: mainDrawer.label = this + + ListModel { + id: paneModel + + ListElement { + txt: "About" + img: "about" + } + + ListElement { + txt: "Help" + img: "help" + } + + ListElement { + txt: "Authors" + img: "author" + } + + ListElement { + txt: "License" + img: "license" + } + + ListElement { + txt: "Support" + img: "support" + } + + ListElement { + txt: "Changes" + img: "changes" + } + + } + + Rectangle { + id: item + + width: parent.height / 2 + height: width * 1.4 + x: parent.width - width - NOO.factor() / 4 + y: -height + radius: width / 8 + color: Qt.rgba(0, 0, 0, 0.8) + + Image { + id: paneImg + + source: NOO.pix("pane/" + paneModel.get(nooLabel.currentItem).img) + height: parent.width + width: height * (sourceSize.width / sourceSize.height) + visible: false + } + + Colorize { + anchors.fill: paneImg + source: paneImg + hue: 0 + lightness: 0.5 + saturation: 0 + } + + Text { + color: nooLabel.bgColor + text: NOO.TR(nooLabel.currentItem === 1 ? "QShortcut" : "TaboutNootka", paneModel.get(nooLabel.currentItem).txt) + width: parent.width + horizontalAlignment: Text.AlignHCenter + fontSizeMode: Text.Fit + minimumPixelSize: NOO.factor() / 2 + + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + } + + } + + SequentialAnimation { + loops: paneModel.count + running: true + + PauseAnimation { + duration: 500 + } + + PropertyAnimation { + target: item + property: "y" + duration: 250 + to: (item.parent.height - item.height) / 2 + } + + PauseAnimation { + duration: 1500 + } + + PropertyAnimation { + target: item + property: "y" + duration: 500 + to: item.parent.height + item.height + } + + ScriptAction { + script: { + item.y = -item.height; + if (nooLabel.currentItem < paneModel.count - 1) + nooLabel.currentItem++; + + } + } + + } + + } + + } + + Repeater { + model: examActions + + MenuButton { + action: modelData + visible: action && action.enabled + + Rectangle { + width: NOO.factor() * 3 + height: parent.height + z: -1 + color: action ? NOO.alpha(action.bgColor, 50) : "transparent" + } + + } + + } + + MenuButton { + visible: !executor || executor.showPitchView + action: pitchDetectAct + } + + MenuButton { + visible: !GLOB.singleNoteMode + action: tempoAct + + Text { + property var beatModel: ["\ue1d5", "\ue1d7", "\ue1d5 \ue1e7", "\ue1d3"] + + x: parent.width - width - NOO.factor() / 2 + y: parent.height * -0.55 + text: beatModel[SOUND.beatUnit] + "=" + SOUND.tempo + + font { + family: "Scorek" + pixelSize: parent.height * 0.6 + } + + } + + } + + MenuButton { + visible: !GLOB.isExam + action: NOO.examAct + } + + MenuButton { + visible: !GLOB.isExam + action: NOO.levelAct + } + + MenuButton { + visible: !GLOB.singleNoteMode + action: NOO.scoreAct + } + + MenuButton { + + action: Taction { + text: NOO.settingsAct.text + icon: GLOB.isExam ? "exam-settings" : "systemsettings" + onTriggered: { + if (GLOB.isExam) + executor.settingsAct.trigger(); + else + NOO.settingsAct.trigger(); + } + } + + } + + MenuButton { + visible: !GLOB.isExam + action: tunerAct + + Text { + x: parent.width - width - NOO.factor() / 4 + y: (parent.height - height) / 2 + text: "A = " + GLOB.midAfreq + + font { + pixelSize: parent.height * 0.55 + bold: true + } + + } + + } + + MenuButton { + onClicked: nootkaWindow.close() + + action: Taction { + icon: "close" + text: NOO.TR("QShortcut", "Close") + } + + } + + } + } - } + } - MenuButton { visible: !executor || executor.showPitchView; action: pitchDetectAct } - MenuButton { - visible: !GLOB.singleNoteMode - action: tempoAct - Text { - property var beatModel: [ "\ue1d5", "\ue1d7", "\ue1d5 \ue1e7", "\ue1d3" ] - x: parent.width - width - NOO.factor() / 2; y: parent.height * -0.55 - font { family: "Scorek"; pixelSize: parent.height * 0.6 } - text: beatModel[SOUND.beatUnit] + "=" + SOUND.tempo - } + + } + + } + + Component { + id: clearComp + + TpopupDialog { + width: footWidth + NOO.factor() + height: clearCol.height + NOO.factor() * 4 + bgColor: Qt.tint(activPal.window, NOO.alpha("orange", 20)) + onAccepted: score.clearScoreAct.trigger() + + border { + color: "orange" + width: NOO.factor() / 4 } - MenuButton { visible: !GLOB.isExam; action: NOO.examAct } - MenuButton { visible: !GLOB.isExam; action: NOO.levelAct } - MenuButton { visible: !GLOB.singleNoteMode; action: NOO.scoreAct } - MenuButton { - action: Taction { - text: NOO.settingsAct.text - icon: GLOB.isExam ? "exam-settings" : "systemsettings" - onTriggered: { - if (GLOB.isExam) - executor.settingsAct.trigger() - else - NOO.settingsAct.trigger() + //modal: true + + Column { + id: clearCol + + anchors.horizontalCenter: parent.horizontalCenter + + Image { + anchors.horizontalCenter: parent.horizontalCenter + source: NOO.pix("clear-score") + height: NOO.factor() * 4 + width: height } - } - } - MenuButton { - visible: !GLOB.isExam - action: tunerAct - Text { - x: parent.width - width - NOO.factor() / 4; y: (parent.height - height) / 2 - font { pixelSize: parent.height * 0.55; bold: true } - text: "A = " + GLOB.midAfreq - } + + Text { + text: NOO.TR("TscoreObject", "Delete all notes") + color: activPal.text + } + } - MenuButton { onClicked: nootkaWindow.close(); action: Taction { icon: "close"; text: NOO.TR("QShortcut", "Close") } } - } + } - } + } - } - - Component { - id: clearComp - TpopupDialog { - width: footWidth + NOO.factor(); height: clearCol.height + NOO.factor() * 4 - bgColor: Qt.tint(activPal.window, NOO.alpha("orange", 20)) - border { color: "orange"; width: NOO.factor() / 4.0 } - //modal: true - Column { - id: clearCol - anchors.horizontalCenter: parent.horizontalCenter - Image { - anchors.horizontalCenter: parent.horizontalCenter - source: NOO.pix("clear-score") - height: NOO.factor() * 4; width: height - } - Text { - text: NOO.TR("TscoreObject", "Delete all notes") - color: activPal.text - } - } - onAccepted: score.clearScoreAct.trigger() + + Connections { + target: SOUND + onVolumeKeyPressed: nootkaWindow.showDialog(Nootka.Tuner) + onListeningChanged: pitchDot.scale = 1 + } + + FlyItem { + taction: fly1act + index: 0 + } + + FlyItem { + taction: fly2act + index: 1 + } + + FlyItem { + taction: fly3act + index: 2 + } + + FlyItem { + taction: fly4act + index: 3 + } + + FlyItem { + taction: fly5act + index: 4 + } + + Timer { + repeat: true + interval: 75 + running: SOUND.listening + onTriggered: pitchDot.scale = 1 + SOUND.inputVol() } - } - - onWantClearScore: { - if (!clearPopup) - clearPopup = clearComp.createObject(nootkaWindow.contentItem) - clearPopup.open() - } - - onFlyClicked: { - if (currentFly) - currentFly.taction.trigger() - } - - Connections { - target: SOUND - onVolumeKeyPressed: nootkaWindow.showDialog(Nootka.Tuner) - onListeningChanged: pitchDot.scale = 1 - } - - FlyItem { taction: fly1act; index: 0 } - FlyItem { taction: fly2act; index: 1 } - FlyItem { taction: fly3act; index: 2 } - FlyItem { taction: fly4act; index: 3 } - FlyItem { taction: fly5act; index: 4 } - - Timer { - repeat: true; interval: 75 - running: SOUND.listening - onTriggered: pitchDot.scale = 1 + SOUND.inputVol() - } } diff --git a/src/qml/+android/StatusTip.qml b/src/qml/+android/StatusTip.qml index e0c07e6b586cc6a13ecf224dc9968b4764f181cf..865d11c8b561234879606ddde51ed9459afba3f7 100644 --- a/src/qml/+android/StatusTip.qml +++ b/src/qml/+android/StatusTip.qml @@ -2,53 +2,66 @@ * Copyright (C) 2018-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 -import Nootka 1.0 +TipRect { + id: statusTip + property alias text: text.text + property int tipPos: Item.Top -TipRect { - id: statusTip + x: 0.1 * nootkaWindow.width + y: statusTip.text === "" ? -1.2 * height : 0 + z: 500 + radius: 0 + width: nootkaWindow.width * 0.8 + height: Math.min(nootkaWindow.height / 6, NOO.factor() * 7) + color: Qt.tint(ma.pressed ? activPal.highlight : activPal.text, NOO.alpha(NOO.messageColor, 100)) - property alias text: text.text - property int tipPos: Item.Top + Connections { + target: NOO + onStatusTip: { + text.textFormat = richText ? Text.RichText : Text.AutoText; + text.text = statusText; + statusTip.tipPos = tipPos; + } + } + + Text { + id: text - Connections { - target: NOO - onStatusTip: { - text.textFormat = richText ? Text.RichText : Text.AutoText - text.text = statusText - statusTip.tipPos = tipPos + padding: statusTip.height / 10 + font.pixelSize: parent.height / 4 + anchors.fill: parent + wrapMode: Text.WordWrap + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + color: ma.pressed ? activPal.highlightedText : activPal.base } - } - - x: 0.1 * nootkaWindow.width; y: statusTip.text === "" ? -1.2 * height : 0 - z: 500; radius: 0 - width: nootkaWindow.width * 0.8 - height: Math.min(nootkaWindow.height / 6, NOO.factor() * 7) - - color: Qt.tint(ma.pressed ? activPal.highlight : activPal.text, NOO.alpha(NOO.messageColor, 100)) - - Text { - id: text - padding: statusTip.height / 10 - font.pixelSize: parent.height / 4 - anchors.fill: parent - wrapMode: Text.WordWrap; verticalAlignment: Text.AlignVCenter; horizontalAlignment: Text.AlignHCenter - color: ma.pressed ? activPal.highlightedText : activPal.base - } - - MouseArea { - id: ma - anchors.fill: parent - onReleased: NOO.setStatusTip("") - } - - Behavior on y { - enabled: GLOB.useAnimations - SequentialAnimation { - PauseAnimation { duration: 150 } - NumberAnimation { easing.type: Easing.OutQuad; duration: 150 } + + MouseArea { + id: ma + + anchors.fill: parent + onReleased: NOO.setStatusTip("") } - } + + Behavior on y { + enabled: GLOB.useAnimations + + SequentialAnimation { + PauseAnimation { + duration: 150 + } + + NumberAnimation { + easing.type: Easing.OutQuad + duration: 150 + } + + } + + } + } diff --git a/src/qml/about/AboutPage.qml b/src/qml/about/AboutPage.qml index 610ef6ee28e35c580ed210b446ec3548f14fe0ee..cd451055b7ccd15637cf34259fc8b5490668fb5e 100644 --- a/src/qml/about/AboutPage.qml +++ b/src/qml/about/AboutPage.qml @@ -2,78 +2,108 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - -import Nootka 1.0 import "../" +import Nootka 1.0 +import QtQuick 2.12 Tflickable { - height: parent.height - - property alias color: nooLab.bgColor - property alias siteAddr: siteAddr - - contentHeight: aboutCol.height - contentWidth: width - - Column { - id: aboutCol - width: parent.width - spacing: NOO.factor() - TipRect { - height: NOO.factor() * (NOO.isAndroid() ? 5 : 7); width: parent.width - color: nooLab.bgColor; radius: 0 - NootkaLabel { - id: nooLab - height: parent.height - active: false - anchors.centerIn: parent - bgColor: NOO.randomColor() - } - MouseArea { - anchors.fill: parent - onClicked: nooLab.bgColor = NOO.randomColor() - hoverEnabled: true - cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor - } - } - LinkText { - id: siteAddr - anchors.horizontalCenter: parent. horizontalCenter - text: ("<a style=\"text-decoration: none; color: %1\" href=\"https://nootka.sourceforge.io\">https://nootka.sourceforge.io</a>").arg(nooLab.bgColor) - textFormat: Text.RichText - font { pixelSize: NOO.factor() * 1.5 } - } - Tile { - bgColor: Qt.tint(nooLab.bgColor, NOO.alpha(activPal.base, 230)) - bgBorder { width: 2; color: nooLab.bgColor } - width: parent.width - NOO.factor() - Column { + property alias color: nooLab.bgColor + property alias siteAddr: siteAddr + + height: parent.height + contentHeight: aboutCol.height + contentWidth: width + + Column { + id: aboutCol + width: parent.width spacing: NOO.factor() - Text { - width: parent.width - font { pixelSize: NOO.factor() * 2; bold: true } - horizontalAlignment: Text.AlignHCenter - text: "Nootka " + NOO.version() - color: activPal.text + + TipRect { + height: NOO.factor() * (NOO.isAndroid() ? 5 : 7) + width: parent.width + color: nooLab.bgColor + radius: 0 + + NootkaLabel { + id: nooLab + + height: parent.height + active: false + anchors.centerIn: parent + bgColor: NOO.randomColor() + } + + MouseArea { + anchors.fill: parent + onClicked: nooLab.bgColor = NOO.randomColor() + hoverEnabled: true + cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + } + } + LinkText { - text: qsTr("Welcome on the board.<br>Nootka is an open source application to help you in learning (and in teaching) classical score notation.") - + "<br><br>" - + qsTr("See a <a href=\"%1\">program site</a> for more details and further releases.<br>Any bugs, suggestions, translations and so on, please report to: %2.<br><br>with respects<br>Author") - .arg("https://nootka.sourceforge.io") - .arg("<a href=\"mailto:seelook.gmail.com\">seelook@gmail.com</a>") - width: parent.width * 0.96 - anchors.horizontalCenter: parent.horizontalCenter - font { pixelSize: NOO.factor() * 1.1 } - horizontalAlignment: Text.AlignLeft - wrapMode: Text.WordWrap + id: siteAddr + + anchors.horizontalCenter: parent.horizontalCenter + text: ("<a style=\"text-decoration: none; color: %1\" href=\"https://nootka.sourceforge.io\">https://nootka.sourceforge.io</a>").arg(nooLab.bgColor) + textFormat: Text.RichText + + font { + pixelSize: NOO.factor() * 1.5 + } + } - } - property string betaText: qsTr("This is a beta version and may contain bugs or behave in unexpected ways. Also, it has unfinished features.<br>In spite of that, you are welcome to try it!") -// description: betaText // uncomment if beta - descriptionColor: "red" + + Tile { + property string betaText: qsTr("This is a beta version and may contain bugs or behave in unexpected ways. Also, it has unfinished features.<br>In spite of that, you are welcome to try it!") + + bgColor: Qt.tint(nooLab.bgColor, NOO.alpha(activPal.base, 230)) + width: parent.width - NOO.factor() + // description: betaText // uncomment if beta + descriptionColor: "red" + + bgBorder { + width: 2 + color: nooLab.bgColor + } + + Column { + width: parent.width + spacing: NOO.factor() + + Text { + width: parent.width + horizontalAlignment: Text.AlignHCenter + text: "Nootka " + NOO.version() + color: activPal.text + + font { + pixelSize: NOO.factor() * 2 + bold: true + } + + } + + LinkText { + text: qsTr("Welcome on the board.<br>Nootka is an open source application to help you in learning (and in teaching) classical score notation.") + "<br><br>" + qsTr("See a <a href=\"%1\">program site</a> for more details and further releases.<br>Any bugs, suggestions, translations and so on, please report to: %2.<br><br>with respects<br>Author").arg("https://nootka.sourceforge.io").arg("<a href=\"mailto:seelook.gmail.com\">seelook@gmail.com</a>") + width: parent.width * 0.96 + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignLeft + wrapMode: Text.WordWrap + + font { + pixelSize: NOO.factor() * 1.1 + } + + } + + } + + } + } - } + } diff --git a/src/qml/about/ChangesPage.qml b/src/qml/about/ChangesPage.qml index 89bf6ca60c5db037ec0a682b1be93f235df2fd2f..594d7c0f84db2ea2913e9c0ffb783fd9c40285aa 100644 --- a/src/qml/about/ChangesPage.qml +++ b/src/qml/about/ChangesPage.qml @@ -2,32 +2,41 @@ * Copyright (C) 2017-2018 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 Nootka 1.0 -import "../" - ListView { - id: chList - width: parent.width; height: parent.height - - model: dialogObj.getChanges() - delegate: Tile { - width: chList.width; height: relText.height + NOO.factor() - bgColor: index % 2 ? activPal.base : activPal.alternateBase - Text { - id: relText - text: modelData - x: NOO.factor() / 2; y: NOO.factor() / 2 - width: chList.width - NOO.factor() - horizontalAlignment: text.substring(0, 4) === "<h1>" ? Text.AlignHCenter : Text.AlignLeft - color: activPal.text - wrapMode: TextEdit.Wrap; textFormat: Text.StyledText - } - } + id: chList - ScrollBar.vertical: ScrollBar { active: true; visible: active } -} + width: parent.width + height: parent.height + model: dialogObj.getChanges() + delegate: Tile { + width: chList.width + height: relText.height + NOO.factor() + bgColor: index % 2 ? activPal.base : activPal.alternateBase + Text { + id: relText + + text: modelData + x: NOO.factor() / 2 + y: NOO.factor() / 2 + width: chList.width - NOO.factor() + horizontalAlignment: text.substring(0, 4) === "<h1>" ? Text.AlignHCenter : Text.AlignLeft + color: activPal.text + wrapMode: TextEdit.Wrap + textFormat: Text.StyledText + } + + } + + ScrollBar.vertical: ScrollBar { + active: true + visible: active + } + +} diff --git a/src/qml/about/DonorsPage.qml b/src/qml/about/DonorsPage.qml index 4fe6414370cbe37f86df5698ffb4fc6aede78d4f..ca98058599ba6a1d713dd7d4b2e320218ed5e251 100644 --- a/src/qml/about/DonorsPage.qml +++ b/src/qml/about/DonorsPage.qml @@ -2,104 +2,149 @@ * 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 Nootka 1.0 -import "../" - Tflickable { - id: root - contentHeight: donCol.height - z: 1 - - Rectangle { - id: bgRect - width: root.width; height: root.height - color: NOO.alpha(activPal.base, 230) - parent: root - z: -1 - Image { - source: NOO.pix("nootka") - height: root.height; width: height - z: -1 - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Column { - id: donCol - width: root.width - spacing: NOO.factor() - z: 2 - - Tile { - width: parent.width - anchors.horizontalCenter: undefined - bgColor: activPal.highlight - Text { - text: qsTranslate("TaboutNootka", "People and companies who gave material support for the Nootka project") - width: parent.width * 0.9 - wrapMode: Text.WordWrap - font { pixelSize: NOO.factor() * 2; bold: true } - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.highlightedText - horizontalAlignment: Text.AlignHCenter - } + id: root + + contentHeight: donCol.height + z: 1 + + Rectangle { + id: bgRect + + width: root.width + height: root.height + color: NOO.alpha(activPal.base, 230) + parent: root + z: -1 + + Image { + source: NOO.pix("nootka") + height: root.height + width: height + z: -1 + anchors.horizontalCenter: parent.horizontalCenter + } + } - Grid { - id: container - width: columns * widest + (columns - 1) * NOO.factor() - columns: Math.floor(parent.width / (widest + NOO.factor())) - horizontalItemAlignment: Grid.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - property real widest: 0 - spacing: NOO.factor() - Repeater { - model: [ "Wolfgang Pflaesterer", "Tony Nederpel", "Jose1711", "Wayne Bonner", "Aaron Wolf", - "Torsten Philipp", "Vincent Bermel", "Tomasz Matuszewski", - "Yves Balhant", "Илья Б.", "...and others" - ] + Column { + id: donCol + + width: root.width + spacing: NOO.factor() + z: 2 + Tile { - id: donTile - z: scale > 1 ? 2 : 1 - anchors.horizontalCenter: undefined - property color randCol: NOO.randomColor() - width: tt.width + NOO.factor() * 4 - bgBorder { color: randCol; width: 2 } - bgColor: Qt.tint(randCol, NOO.alpha(activPal.base, 180)) - Text { - id: tt - font.pixelSize: NOO.factor() * 1.5 - text: modelData + width: parent.width + anchors.horizontalCenter: undefined + bgColor: activPal.highlight + + Text { + text: qsTranslate("TaboutNootka", "People and companies who gave material support for the Nootka project") + width: parent.width * 0.9 + wrapMode: Text.WordWrap + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.highlightedText + horizontalAlignment: Text.AlignHCenter + + font { + pixelSize: NOO.factor() * 2 + bold: true + } + + } + + } + + Grid { + id: container + + property real widest: 0 + + width: columns * widest + (columns - 1) * NOO.factor() + columns: Math.floor(parent.width / (widest + NOO.factor())) + horizontalItemAlignment: Grid.AlignHCenter + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() + + Repeater { + model: ["Wolfgang Pflaesterer", "Tony Nederpel", "Jose1711", "Wayne Bonner", "Aaron Wolf", "Torsten Philipp", "Vincent Bermel", "Tomasz Matuszewski", "Yves Balhant", "Илья Б.", "...and others"] + + Tile { + id: donTile + + property color randCol: NOO.randomColor() + + z: scale > 1 ? 2 : 1 + anchors.horizontalCenter: undefined + width: tt.width + NOO.factor() * 4 + bgColor: Qt.tint(randCol, NOO.alpha(activPal.base, 180)) + + bgBorder { + color: randCol + width: 2 + } + + Text { + id: tt + + font.pixelSize: NOO.factor() * 1.5 + text: modelData + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + Component.onCompleted: container.widest = Math.max(container.widest, tt.width + NOO.factor() * 4) + } + + MouseArea { + id: ma + + anchors.fill: parent + hoverEnabled: true + onEntered: { + randCol = NOO.randomColor(); + donTile.scale = 1.5; + } + onExited: donTile.scale = 1 + onClicked: randCol = NOO.randomColor() + } + + Behavior on randCol { + ColorAnimation { + duration: 300 + } + + } + + Behavior on scale { + NumberAnimation { + duration: 300 + } + + } + + } + + } + + } + + Text { + text: "THANK YOU! " anchors.horizontalCenter: parent.horizontalCenter color: activPal.text - Component.onCompleted: container.widest = Math.max(container.widest, tt.width + NOO.factor() * 4) - } - MouseArea { - id: ma - anchors.fill: parent - hoverEnabled: true - onEntered: { - randCol = NOO.randomColor() - donTile.scale = 1.5 + + font { + bold: true + pixelSize: NOO.factor() * 2 } - onExited: donTile.scale = 1 - onClicked: randCol = NOO.randomColor() - } - Behavior on randCol { ColorAnimation { duration: 300 }} - Behavior on scale { NumberAnimation { duration: 300}} + } - } - } - Text { - font { bold: true; pixelSize: NOO.factor() * 2 } - text: "THANK YOU! " - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text } - } -} +} diff --git a/src/qml/about/HelpPage.qml b/src/qml/about/HelpPage.qml index 53e64f37022ffb66afef7863186a5b5997c6d251..bb122ec4741435aeefc02609f68aec5d1e407780 100644 --- a/src/qml/about/HelpPage.qml +++ b/src/qml/about/HelpPage.qml @@ -2,124 +2,169 @@ * 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 Nootka 1.0 -import "../" +Rectangle { + property string helpText: mainHelpText //* @p mainHelpText has to be defined somewhere above + property alias enableTOC: tocButt.visible + property var topics: [qsTranslate("ThelpDialogBase", "Nootka help"), qsTranslate("TstartExamDlg", "To exercise or to pass an exam?"), qsTranslate("TexamHelp", "How does an exercise or an exam work?"), NOO.TR("MainMenuMobile", "Pitch recognition"), NOO.TR("NoteSelected", "Note selection and playing"), NOO.TR("HandleScore", "Editing score with touch"), qsTranslate("ThelpDialogBase", "Open online documentation")] + property int currTopic: 0 + property var gotItQML: ["", "ExamOrExercise", "ExamFlow", "SoundInfo", "NoteSelected", "HandleScore"] + property var gotItObj: [null, null, null, null, null, null] + function switchTopic(tp) { + if (tp !== currTopic) { + if (tp === topics.length - 1) { + NOO.openDocLink("2017/05/17/getting-started/"); + } else { + if (tp > 0) { + if (!gotItObj[tp]) + gotItObj[tp] = Qt.createComponent("qrc:/gotit/" + gotItQML[tp] + ".qml").createObject(stack, { + "visible": false, + "showGotIt": false + }); + else + gotItObj[tp].start(); + stack.replace(gotItObj[tp].contentItem); + if (currTopic > 0) + gotItObj[currTopic].stop(); + + } else { + stack.replace(mainHelp); + } + currTopic = tp; + } + } + tocMenu.close(); + } + + width: parent.width + height: parent.height + color: NOO.alpha(activPal.base, 240) + z: 0 + Component.onCompleted: { + if (enableTOC) + tocRep.model = topics; -Rectangle { - property string helpText: mainHelpText /** @p mainHelpText has to be defined somewhere above */ - property alias enableTOC: tocButt.visible - - width: parent.width; height: parent.height - color: NOO.alpha(activPal.base, 240) - z: 0 - Image { - source: currTopic ? "" : NOO.pix("help") - height: parent.height * Math.min(1, (parent.width / parent.height) / (sourceSize.width / sourceSize.height)) - width: height * (sourceSize.width / sourceSize.height) - z: -1 - anchors.centerIn: parent - } - - TcuteButton { - id: tocButt - y: NOO.factor() / 4; x: parent.width - width - NOO.factor() - z: 10 - text: qsTr("Help topics").replace(" ", "\n") - onClicked: tocMenu.open() - } - - StackView { - id: stack - anchors.fill: parent - initialItem: mainHelp - replaceEnter: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "y"; from: -height; to: 0 }} - replaceExit: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "y"; from: 0; to: height }} - } - - Component { - id: mainHelp - Tflickable { - y: (tocButt.visible ? tocButt.height : 0) + NOO.factor() - width: parent ? parent.width : 0; height: parent ? parent.height - y : 0 - contentHeight: text.height; - LinkText { - id: text - width: parent.width - padding: NOO.factor() - wrapMode: TextEdit.Wrap; textFormat: Text.RichText - text: helpText - } } - } - - property var topics: [ qsTranslate("ThelpDialogBase", "Nootka help"), - qsTranslate("TstartExamDlg", "To exercise or to pass an exam?"), - qsTranslate("TexamHelp", "How does an exercise or an exam work?"), - NOO.TR("MainMenuMobile", "Pitch recognition"), - NOO.TR("NoteSelected", "Note selection and playing"), - NOO.TR("HandleScore", "Editing score with touch"), - qsTranslate("ThelpDialogBase", "Open online documentation") - ] - property int currTopic: 0 - property var gotItQML: [ "", "ExamOrExercise", "ExamFlow", "SoundInfo", "NoteSelected", "HandleScore" ] - property var gotItObj: [ null, null, null, null, null, null ] - - Component.onCompleted: { - if (enableTOC) - tocRep.model = topics - } - - Tmenu { - id: tocMenu - width: NOO.factor() * 25 - x: parent.width - width - y; y: NOO.factor() / 2 - Repeater { - id: tocRep - MenuItem { - padding: 0 - contentItem: MenuButton { - action: Taction { - text: (currTopic === index ? "<u>" : "") + modelData + (currTopic === index ? "</u>" : "") - icon: index ? "" : "help" - } - onClicked: switchTopic(index) - Rectangle { width: parent.width; height: index === topics.length - 1 ? 0 : 1; color: activPal.text; y: parent.height - 1 } + onVisibleChanged: { + // stop/start animation when user switches to/from another About page + if (currTopic > 0 && currTopic < topics.length - 1) { + if (visible) + gotItObj[currTopic].start(); + else + gotItObj[currTopic].stop(); } - } } - } - - onVisibleChanged: { // stop/start animation when user switches to/from another About page - if (currTopic > 0 && currTopic < topics.length - 1) { - if (visible) - gotItObj[currTopic].start() - else - gotItObj[currTopic].stop() + + Image { + source: currTopic ? "" : NOO.pix("help") + height: parent.height * Math.min(1, (parent.width / parent.height) / (sourceSize.width / sourceSize.height)) + width: height * (sourceSize.width / sourceSize.height) + z: -1 + anchors.centerIn: parent } - } - - function switchTopic(tp) { - if (tp !== currTopic) { - if (tp === topics.length - 1) { - NOO.openDocLink("2017/05/17/getting-started/") - } else { - if (tp > 0) { - if (!gotItObj[tp]) - gotItObj[tp] = Qt.createComponent("qrc:/gotit/" + gotItQML[tp] + ".qml").createObject(stack, { "visible": false, "showGotIt": false }) - else - gotItObj[tp].start() - stack.replace(gotItObj[tp].contentItem) - if (currTopic > 0) - gotItObj[currTopic].stop() - } else - stack.replace(mainHelp) - currTopic = tp - } + + TcuteButton { + id: tocButt + + y: NOO.factor() / 4 + x: parent.width - width - NOO.factor() + z: 10 + text: qsTr("Help topics").replace(" ", "\n") + onClicked: tocMenu.open() } - tocMenu.close() - } + + StackView { + id: stack + + anchors.fill: parent + initialItem: mainHelp + + replaceEnter: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "y" + from: -height + to: 0 + } + + } + + replaceExit: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "y" + from: 0 + to: height + } + + } + + } + + Component { + id: mainHelp + + Tflickable { + y: (tocButt.visible ? tocButt.height : 0) + NOO.factor() + width: parent ? parent.width : 0 + height: parent ? parent.height - y : 0 + contentHeight: text.height + + LinkText { + id: text + + width: parent.width + padding: NOO.factor() + wrapMode: TextEdit.Wrap + textFormat: Text.RichText + text: helpText + } + + } + + } + + Tmenu { + id: tocMenu + + width: NOO.factor() * 25 + x: parent.width - width - y + y: NOO.factor() / 2 + + Repeater { + id: tocRep + + MenuItem { + padding: 0 + + contentItem: MenuButton { + onClicked: switchTopic(index) + + Rectangle { + width: parent.width + height: index === topics.length - 1 ? 0 : 1 + color: activPal.text + y: parent.height - 1 + } + + action: Taction { + text: (currTopic === index ? "<u>" : "") + modelData + (currTopic === index ? "</u>" : "") + icon: index ? "" : "help" + } + + } + + } + + } + + } + } diff --git a/src/qml/about/LicensePage.qml b/src/qml/about/LicensePage.qml index 46ce759e9b03f8702adf3135a2c5e775fb28b24d..c9072cf42f2fcd5712ca3d718f8c52f25f9ccdb3 100644 --- a/src/qml/about/LicensePage.qml +++ b/src/qml/about/LicensePage.qml @@ -2,28 +2,30 @@ * Copyright (C) 2017-2019 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" import QtQuick 2.12 import QtQuick.Controls 2.12 -import "../" +Tflickable { + id: flick + contentHeight: text.paintedHeight + contentWidth: flick.width -Tflickable { - id: flick - contentHeight: text.paintedHeight; contentWidth: flick.width + Rectangle { + anchors.fill: parent + color: activPal.base + } + + TextEdit { + id: text - Rectangle { - anchors.fill: parent - color: activPal.base - } + textMargin: font.pixelSize + width: flick.width + wrapMode: TextEdit.Wrap + readOnly: true + color: activPal.text + text: dialogObj.getLicense() + } - TextEdit { - id: text - textMargin: font.pixelSize - width: flick.width - wrapMode: TextEdit.Wrap - readOnly: true - color: activPal.text - text: dialogObj.getLicense() - } } diff --git a/src/qml/about/QtPage.qml b/src/qml/about/QtPage.qml index a8ea477d63f682cf441274e4893a6298f60e94c5..de5b53f7b7ddf7c2f78223155ff462c4db238442 100644 --- a/src/qml/about/QtPage.qml +++ b/src/qml/about/QtPage.qml @@ -2,20 +2,21 @@ * 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 Nootka 1.0 -import "../" - Tflickable { - contentHeight: text.height; + contentHeight: text.height + + LinkText { + id: text + + width: parent.width + padding: NOO.factor() + wrapMode: TextEdit.Wrap + text: dialogObj.aboutQt() + } - LinkText { - id: text - width: parent.width - padding: NOO.factor() - wrapMode: TextEdit.Wrap - text: dialogObj.aboutQt() - } } diff --git a/src/qml/about/SupportPage.qml b/src/qml/about/SupportPage.qml index 3881c9caaa616b8c900795e5e956e56ae19d79e3..5bfefdb0f7c73a0003687c45e9d80872a4e04c99 100644 --- a/src/qml/about/SupportPage.qml +++ b/src/qml/about/SupportPage.qml @@ -2,141 +2,207 @@ * 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 Nootka 1.0 -import "../" - Tflickable { - height: parent.height - contentHeight: suppFlow.childrenRect.height + thText.height + NOO.factor() * 3 - contentWidth: width + height: parent.height + contentHeight: suppFlow.childrenRect.height + thText.height + NOO.factor() * 3 + contentWidth: width - Flow { - id: suppFlow - width: parent.width - NOO.factor() * 2 - height: childrenRect.height - anchors { margins: NOO.factor(); horizontalCenter: parent.horizontalCenter } - spacing: NOO.factor() / 2 + Flow { + id: suppFlow - Tile { - width: parent.width - anchors.horizontalCenter: undefined - bgColor: activPal.highlight - Text { - text: qsTr("You also can help with making Nootka better.") - width: parent.width * 0.9 - wrapMode: Text.WordWrap - font { pixelSize: NOO.factor() * 2; bold: true } - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.highlightedText - } - } - Tile { - anchors.horizontalCenter: undefined - bgBorder { color: activPal.highlight; width: 2 } - Text { - width: parent.width * 0.96 - text: qsTr("It requires little bit English, so if you can read a text below there will be something you may get involved.") - font { pixelSize: NOO.factor() * 1.1 } - wrapMode: Text.WordWrap - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text - } - } + width: parent.width - NOO.factor() * 2 + height: childrenRect.height + spacing: NOO.factor() / 2 + + anchors { + margins: NOO.factor() + horizontalCenter: parent.horizontalCenter + } + + Tile { + width: parent.width + anchors.horizontalCenter: undefined + bgColor: activPal.highlight + + Text { + text: qsTr("You also can help with making Nootka better.") + width: parent.width * 0.9 + wrapMode: Text.WordWrap + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.highlightedText + + font { + pixelSize: NOO.factor() * 2 + bold: true + } + + } + + } + + Tile { + anchors.horizontalCenter: undefined + + bgBorder { + color: activPal.highlight + width: 2 + } + + Text { + width: parent.width * 0.96 + text: qsTr("It requires little bit English, so if you can read a text below there will be something you may get involved.") + wrapMode: Text.WordWrap + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + + font { + pixelSize: NOO.factor() * 1.1 + } + + } + + } + + ListModel { + //ListElement "Express your opinion" D 8 | A 7 + + id: suppModel + + Component.onCompleted: { + // HACK: ListElement can handle only static data, but not any function like qsTr or so. + // So insert/append such a data with script here + if (!NOO.isAndroid()) + insert(0, { + "accent": "#42DA06", + "header": qsTr("Donate Nootka campaign"), + "message": "<a href=\"https://nootka.sourceforge.io/index.php?C=donate\">" + qsTr("Through PayPal or a card") + "</a><br><a href=\"mailto:seelook.gmail.com\">" + qsTr("or send email for an account number") + "</a>" + }); - ListModel { - id: suppModel - // desktop | Android - //ListElement qsTr("Donate Nootka campaign") : onCompleted | D 0 - ListElement { // D 1 | A 0 - accent: "#930000" - header: "Record audio samples" - message: "Nootka uses natural sounds,<br>so audio samples of bandoneon and saxophones are needed.<br>Also new ones of electric and bass guitar will be needed soon.<br>Home made samples should be sufficient.<br><a href=\"https://www.opencode.net/seelook/nootka/blob/master/CONTRIBUTING.md#record\">Take a look here</a> or just <a href=\"mailto:seelook.gmail.com\">write message</a> for details." - } - ListElement { // D 2 | A 1 - accent: "#0000C0" - header: "Translate Nootka" - message: "It does not require any programming skills.<br>Just read <a href=\"https://www.opencode.net/seelook/nootka/blob/master/lang/how-to-translate.md\">the instructions</a>,<br>translate and send your work." - } - ListElement { // D 3 | A 2 - accent: "#888888" - header: "Mac needs feedback" - message: "Mac Os version is a new thing.<br>Let us know does Nootka work there or not." - } - //ListElement { NOO.isAndroid() ? "Rate this app" : "Vote on Nootka" // D 4 | A 3 - ListElement { // D 5 | A 4 - accent: "teal" - header: "Create a tutorial" - message: "Take some use case and make video of it or write it down with a few screenshots.<br>Send it somewhere (YouTube, some blog) or here, to Nootka.<br>It may help others a lot." - } - ListElement { // D 6 | A 5 - accent: "#fff" - header: "$> Hacking Nootka code" - message: "<font color=\"#fff\">If You know QML or C++ You could give a hand.<br> + insert(NOO.isAndroid() ? 2 : 3, { + "accent": "#C000C0", + "header": NOO.isAndroid() ? "Rate this app" : "Vote on Nootka", + "message": NOO.isAndroid() ? "Go to <a href=\"https://play.google.com/store/apps/details?id=net.sf.nootka\">Google Play</a>,<br>rate it nicely and put a comment in your native language." : "There are a lot of services. For example:<br><a href=\"https://play.google.com/store/apps/details?id=net.sf.nootka\">Google Play</a>, <a href=\"https://www.linux-apps.com/p/1127020/\">Linux Apps</a>, <a href=\"http://www.softpedia.com/get/Others/Home-Education/Nootka.shtml\">Softpedia</a>" + }); + append({ + "accent": "#000", + "header": "Express your opinion", + "message": "Simply <a href=\"mailto:seelook.gmail.com\">send an email</a>" + }); + get(count - 1).accent = activPal.text; + } + + // desktop | Android + //ListElement qsTr("Donate Nootka campaign") : onCompleted | D 0 + ListElement { + // D 1 | A 0 + accent: "#930000" + header: "Record audio samples" + message: "Nootka uses natural sounds,<br>so audio samples of bandoneon and saxophones are needed.<br>Also new ones of electric and bass guitar will be needed soon.<br>Home made samples should be sufficient.<br><a href=\"https://www.opencode.net/seelook/nootka/blob/master/CONTRIBUTING.md#record\">Take a look here</a> or just <a href=\"mailto:seelook.gmail.com\">write message</a> for details." + } + + // D 2 | A 1 + ListElement { + accent: "#0000C0" + header: "Translate Nootka" + message: "It does not require any programming skills.<br>Just read <a href=\"https://www.opencode.net/seelook/nootka/blob/master/lang/how-to-translate.md\">the instructions</a>,<br>translate and send your work." + } + + // D 3 | A 2 + ListElement { + accent: "#888888" + header: "Mac needs feedback" + message: "Mac Os version is a new thing.<br>Let us know does Nootka work there or not." + } + + //ListElement { NOO.isAndroid() ? "Rate this app" : "Vote on Nootka" // D 4 | A 3 + ListElement { + // D 5 | A 4 + accent: "teal" + header: "Create a tutorial" + message: "Take some use case and make video of it or write it down with a few screenshots.<br>Send it somewhere (YouTube, some blog) or here, to Nootka.<br>It may help others a lot." + } + + // D 6 | A 5 + ListElement { + accent: "#fff" + header: "$> Hacking Nootka code" + message: "<font color=\"#fff\">If You know QML or C++ You could give a hand.<br> <a href=\"https://www.opencode.net/seelook/nootka/blob/master/CONTRIBUTING.md#record\">Visit this link for further instructions.</a></font>" - } - ListElement { // D 7 | A 6 - accent: "#FF0000" - header: "Report an issue" - message: "If you find any issue or a bug than request it through:<br><a href=\"https://sourceforge.net/p/nootka/bugs/\">bug tracker</a>" - } - //ListElement "Express your opinion" D 8 | A 7 - - Component.onCompleted: { - // HACK: ListElement can handle only static data, but not any function like qsTr or so. - // So insert/append such a data with script here - if (!NOO.isAndroid()) { - insert(0, { - "accent": "#42DA06", "header": qsTr("Donate Nootka campaign"), - "message": "<a href=\"https://nootka.sourceforge.io/index.php?C=donate\">" + qsTr("Through PayPal or a card") + "</a><br><a href=\"mailto:seelook.gmail.com\">" + qsTr("or send email for an account number") + "</a>" - }) + } + + // D 7 | A 6 + ListElement { + accent: "#FF0000" + header: "Report an issue" + message: "If you find any issue or a bug than request it through:<br><a href=\"https://sourceforge.net/p/nootka/bugs/\">bug tracker</a>" + } + + } + + Repeater { + model: suppModel + + Tile { + width: tt.width + NOO.factor() * 4 + anchors.horizontalCenter: undefined + bgColor: Qt.tint(accent, Qt.rgba(activPal.base.r, activPal.base.g, activPal.base.b, 0.9)) + Component.onCompleted: { + if (accent === "#fff") + bgColor = "#000"; + // hacking bg color is black + } + + bgBorder { + color: accent + width: 2 + } + + LinkText { + id: tt + + text: "<b><font size=\"5\" color=\"" + accent + "\">" + header + "</font></b><br>" + message + anchors.horizontalCenter: parent.horizontalCenter + } + + } + } - insert(NOO.isAndroid() ? 2 : 3, { - "accent": "#C000C0", "header": NOO.isAndroid() ? "Rate this app" : "Vote on Nootka", - "message": NOO.isAndroid() ? - "Go to <a href=\"https://play.google.com/store/apps/details?id=net.sf.nootka\">Google Play</a>,<br>rate it nicely and put a comment in your native language." : - "There are a lot of services. For example:<br><a href=\"https://play.google.com/store/apps/details?id=net.sf.nootka\">Google Play</a>, <a href=\"https://www.linux-apps.com/p/1127020/\">Linux Apps</a>, <a href=\"http://www.softpedia.com/get/Others/Home-Education/Nootka.shtml\">Softpedia</a>" - }) - append({ "accent": "#000", "header": "Express your opinion", "message": "Simply <a href=\"mailto:seelook.gmail.com\">send an email</a>" }) - get(count - 1).accent = activPal.text - } + } - Repeater { - model: suppModel - Tile { - width: tt.width + NOO.factor() * 4 - anchors.horizontalCenter: undefined - bgBorder { color: accent; width: 2 } - bgColor: Qt.tint(accent, Qt.rgba(activPal.base.r, activPal.base.g, activPal.base.b, 0.9)) - LinkText { - id: tt - text: "<b><font size=\"5\" color=\"" + accent + "\">" + header + "</font></b><br>" + message - anchors.horizontalCenter: parent.horizontalCenter + Tile { + width: NOO.factor() * 20 + bgColor: activPal.highlight + + anchors { + horizontalCenter: parent.horizontalCenter + top: suppFlow.bottom } - Component.onCompleted: { - if (accent === "#fff") - bgColor = "#000" // hacking bg color is black + + bgBorder { + color: activPal.highlightedText + width: 2 + } + + Text { + id: thText + + text: "Thanks in advance!<br>Author" + horizontalAlignment: Text.AlignRight + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.highlightedText + + font { + pixelSize: NOO.factor() * 1.7 + } + } - } - } - } - - Tile { - width: NOO.factor() * 20 - anchors { horizontalCenter: parent.horizontalCenter; top: suppFlow.bottom } - bgColor: activPal.highlight - bgBorder { color: activPal.highlightedText; width: 2 } - Text { - id: thText - text: "Thanks in advance!<br>Author" - font { pixelSize: NOO.factor() * 1.7 } - horizontalAlignment: Text.AlignRight - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.highlightedText } - } + } diff --git a/src/qml/about/SupportPopup.qml b/src/qml/about/SupportPopup.qml index b98e8413fdf4d4bb9888633cd4f81b895386887b..330d498bb568214915b756ea532a955283eea12e 100644 --- a/src/qml/about/SupportPopup.qml +++ b/src/qml/about/SupportPopup.qml @@ -2,42 +2,53 @@ * 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 Nootka 1.0 import "../" - +import Nootka 1.0 +import QtQuick 2.12 TpopupDialog { + property bool bigScr: NOO.shortScreenSide() / NOO.fingerPixels() >= 12 // 8,4 cm width, 7" screens + + caption: NOO.TR("TaboutNootka", "Support") + visible: true + modal: false + width: bigScr ? parent.width * 0.9 : parent.width - NOO.factor() + height: bigScr ? parent.height * 0.9 : parent.height - NOO.factor() + acceptButton.text: NOO.TR("GotIt", "GOT IT!") + rejectButton.visible: false + bgColor: Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 20)) + glowRect.radius: NOO.factor() * 2 + onClosed: destroy() + + border { + color: activPal.highlight + width: NOO.factor() / 4 + } + + Rectangle { + id: bgRect - property bool bigScr: NOO.shortScreenSide() / NOO.fingerPixels() >= 12 // 8,4 cm width, 7" screens + width: parent.width + height: parent.height + color: NOO.alpha(activPal.base, 230) + z: -1 - caption: NOO.TR("TaboutNootka", "Support") + Image { + source: NOO.pix("pane/support") + height: Math.min(parent.width, parent.height) / 2 + width: height + z: -1 - visible: true; modal: false - width: bigScr ? parent.width * 0.9 : parent.width - NOO.factor() - height: bigScr ? parent.height * 0.9 : parent.height - NOO.factor() + anchors { + right: parent.right + bottom: parent.bottom + } - acceptButton.text: NOO.TR("GotIt", "GOT IT!") - rejectButton.visible: false + } - bgColor: Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 20)) - border { color: activPal.highlight; width: NOO.factor() / 4.0 } - glowRect.radius: NOO.factor() * 2 + SupportPage { + } - Rectangle { - id: bgRect - width: parent.width; height: parent.height - color: NOO.alpha(activPal.base, 230) - z: -1 - Image { - anchors { right: parent.right; bottom: parent.bottom } - source: NOO.pix("pane/support") - height: Math.min(parent.width, parent.height) / 2; width: height - z: -1 } - SupportPage {} - } - onClosed: destroy() } diff --git a/src/qml/about/TaboutNootka.qml b/src/qml/about/TaboutNootka.qml index 0cfe4279a90832ad6e6ea74dc6ddb33e546352d4..f24cf5c8ba4d4e0781c828cad3605121def81ea6 100644 --- a/src/qml/about/TaboutNootka.qml +++ b/src/qml/about/TaboutNootka.qml @@ -2,36 +2,35 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 - -import Nootka 1.0 import "about" Item { - width: parent.width - height: parent.height + property string mainHelpText: dialLoader.dialogObj.mainHelp() - property string mainHelpText: dialLoader.dialogObj.mainHelp() + function showPage(pageId) { + pages.selectPage(pageId); + } - PagesDialog { id: pages } + width: parent.width + height: parent.height + Component.onCompleted: { + pages.addItem("about", qsTr("About"), "about/About"); + pages.addItem("help", NOO.TR("QShortcut", "Help"), "about/Help"); + pages.addItem("author", qsTr("Authors"), "about/Authors"); + pages.addItem("license", qsTr("License"), "about/License"); + pages.addItem("support", qsTr("Support"), "about/Support"); + pages.addItem("donors", qsTr("Donors", "Would be 'Sponsors' or even 'Backers' - translate as such as You fill, what sounds/looks better in Your language"), "about/Donors"); + pages.addItem("changes", qsTr("Changes"), "about/Changes"); + pages.addItem("qt", "Qt", "about/Qt"); + dialLoader.standardButtons = DialogButtonBox.Close; + dialLoader.title = qsTr("About Nootka"); + } - Component.onCompleted: { - pages.addItem("about", qsTr("About"), "about/About") - pages.addItem("help", NOO.TR("QShortcut", "Help"), "about/Help") - pages.addItem("author", qsTr("Authors"), "about/Authors") - pages.addItem("license", qsTr("License"), "about/License") - pages.addItem("support", qsTr("Support"), "about/Support") - pages.addItem("donors", - qsTr("Donors", "Would be 'Sponsors' or even 'Backers' - translate as such as You fill, what sounds/looks better in Your language"), - "about/Donors") - pages.addItem("changes", qsTr("Changes"), "about/Changes") - pages.addItem("qt", "Qt", "about/Qt") - dialLoader.standardButtons = DialogButtonBox.Close - dialLoader.title = qsTr("About Nootka") - } + PagesDialog { + id: pages + } - function showPage(pageId) { - pages.selectPage(pageId) - } } diff --git a/src/qml/about/TextBackground.qml b/src/qml/about/TextBackground.qml index 856ee93d95ceb154a74a2d15680708034a7490c5..a0c098fe71e53d4d5be7606ae353f02403f9acb2 100644 --- a/src/qml/about/TextBackground.qml +++ b/src/qml/about/TextBackground.qml @@ -2,21 +2,26 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - -import Nootka 1.0 import "../" +import Nootka 1.0 +import QtQuick 2.12 Text { - font { pixelSize: NOO.factor() * 1.6; bold: true } anchors.horizontalCenter: parent.horizontalCenter textFormat: Text.StyledText color: activPal.highlight + font { + pixelSize: NOO.factor() * 1.6 + bold: true + } + Rectangle { - x: (parent.width - width + NOO.factor()) / 2 - y: NOO.factor() * 2 - color: activPal.highlight - width: authorsPage.width - NOO.factor(); height: NOO.factor() / 12 + x: (parent.width - width + NOO.factor()) / 2 + y: NOO.factor() * 2 + color: activPal.highlight + width: authorsPage.width - NOO.factor() + height: NOO.factor() / 12 } + } diff --git a/src/qml/exam/Certificate.qml b/src/qml/exam/Certificate.qml index c22312f025b1efd47b08482d8928d97669720511..1b2fe654567a7c5e54ebf800dc4d720e1114123d 100644 --- a/src/qml/exam/Certificate.qml +++ b/src/qml/exam/Certificate.qml @@ -2,131 +2,202 @@ * 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 Qt5Compat.GraphicalEffects - +import "../" import Nootka 1.0 import Nootka.Exam 1.0 -import "../" - +import Qt5Compat.GraphicalEffects +import QtQuick 2.12 Item { - anchors.fill: parent + anchors.fill: parent + z: 300 - z: 300 + ShaderEffectSource { + id: effectSource - ShaderEffectSource { - id: effectSource - sourceItem: nootkaWindow.contentItem.parent - anchors.fill: parent - live: false - } + sourceItem: nootkaWindow.contentItem.parent + anchors.fill: parent + live: false + } - Colorize { - anchors.fill: parent - source: effectSource - hue: 0; saturation: 0; lightness: 0 // always black, palette no matters - } - - FastBlur { - id: blur - radius: 36 - } - - MouseArea { anchors.fill: parent; hoverEnabled: true } - - /** apply blur with a delay, otherwise it won't work */ - Timer { - id: timer - interval: 20; running: true - onTriggered: { - blur.source = effectSource - blur.width = Qt.binding( function() { return nootkaWindow.width }) - blur.height = Qt.binding( function() { return nootkaWindow.height }) + Colorize { + anchors.fill: parent + source: effectSource + hue: 0 // always black, palette no matters + saturation: 0 + lightness: 0 } - } - - CertificateItem { - id: cert - parentHeight: parent.height * 0.98 + (parent.width - parent.width) - x: parent.width - width - NOO.factor() / 2; y: (parent.height - height) / 2 - } - - Tile { - anchors.horizontalCenter: undefined - width: parent.width * 0.48; x: parent.width * 0.005; y: parent.height * 0.01 - bgColor: Qt.tint(GLOB.correctColor, NOO.alpha(activPal.base, 180)); bgBorder { color: GLOB.correctColor; width: 2 } - Column { - width: parent.width - Text { - text: qsTranslate("TnootkaCertificate", "CONGRATULATIONS!<br>You have just passed the exam!") - width: parent.width * 0.99 - font { pixelSize: width / 25; bold: true } - horizontalAlignment: Text.AlignHCenter; wrapMode: Text.WordWrap - } - Image { - source: NOO.pix("save") - height: parent.width / 12; width: height * (sourceSize.width / sourceSize.height) - anchors.horizontalCenter: parent.horizontalCenter - } + + FastBlur { + id: blur + + radius: 36 } - description: qsTranslate("TnootkaCertificate", "Save this certificate to file in remembrance.") + MouseArea { - anchors.fill: parent - hoverEnabled: true - onClicked: cert.save() - cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + anchors.fill: parent + hoverEnabled: true } - } - - Tile { - anchors { horizontalCenter: undefined; verticalCenter: parent.verticalCenter } - width: parent.width * 0.48; x: parent.width * 0.005 - bgColor: Qt.tint("blue", NOO.alpha(activPal.base, 180)); bgBorder { color: "blue"; width: 2 } - Column { - width: parent.width - Text { - text: qsTranslate("TnootkaCertificate", "You can still play with it and improve effectiveness.") - width: parent.width * 0.99 - horizontalAlignment: Text.AlignHCenter; wrapMode: Text.WordWrap - } - Image { - source: NOO.pix("nextQuest") - height: parent.width / 12; width: height * (sourceSize.width / sourceSize.height) - anchors.horizontalCenter: parent.horizontalCenter - } + + //* apply blur with a delay, otherwise it won't work + Timer { + id: timer + + interval: 20 + running: true + onTriggered: { + blur.source = effectSource; + blur.width = Qt.binding(function() { + return nootkaWindow.width; + }); + blur.height = Qt.binding(function() { + return nootkaWindow.height; + }); + } } - MouseArea { - anchors.fill: parent - hoverEnabled: true - onClicked: cert.continueExam() - cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + + CertificateItem { + id: cert + + parentHeight: parent.height * 0.98 + (parent.width - parent.width) + x: parent.width - width - NOO.factor() / 2 + y: (parent.height - height) / 2 + } + + Tile { + anchors.horizontalCenter: undefined + width: parent.width * 0.48 + x: parent.width * 0.005 + y: parent.height * 0.01 + bgColor: Qt.tint(GLOB.correctColor, NOO.alpha(activPal.base, 180)) + description: qsTranslate("TnootkaCertificate", "Save this certificate to file in remembrance.") + + bgBorder { + color: GLOB.correctColor + width: 2 + } + + Column { + width: parent.width + + Text { + text: qsTranslate("TnootkaCertificate", "CONGRATULATIONS!<br>You have just passed the exam!") + width: parent.width * 0.99 + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + + font { + pixelSize: width / 25 + bold: true + } + + } + + Image { + source: NOO.pix("save") + height: parent.width / 12 + width: height * (sourceSize.width / sourceSize.height) + anchors.horizontalCenter: parent.horizontalCenter + } + + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + onClicked: cert.save() + cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + } + } - } - - Tile { - anchors.horizontalCenter: undefined - width: parent.width * 0.48; x: parent.width * 0.005; y: parent.height * 0.99 - height - bgColor: Qt.tint(GLOB.wrongColor, NOO.alpha(activPal.base, 180)); bgBorder { color: GLOB.wrongColor; width: 2 } - Column { - width: parent.width - Text { - text: qsTr("Stop exam") - width: parent.width * 0.99 - font { pixelSize: width / 25; bold: true } - horizontalAlignment: Text.AlignHCenter; wrapMode: Text.WordWrap - } - Image { - source: NOO.pix("stopExam") - height: parent.width / 12; width: height * (sourceSize.width / sourceSize.height) - anchors.horizontalCenter: parent.horizontalCenter - } + + Tile { + width: parent.width * 0.48 + x: parent.width * 0.005 + bgColor: Qt.tint("blue", NOO.alpha(activPal.base, 180)) + + anchors { + horizontalCenter: undefined + verticalCenter: parent.verticalCenter + } + + bgBorder { + color: "blue" + width: 2 + } + + Column { + width: parent.width + + Text { + text: qsTranslate("TnootkaCertificate", "You can still play with it and improve effectiveness.") + width: parent.width * 0.99 + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + } + + Image { + source: NOO.pix("nextQuest") + height: parent.width / 12 + width: height * (sourceSize.width / sourceSize.height) + anchors.horizontalCenter: parent.horizontalCenter + } + + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + onClicked: cert.continueExam() + cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + } + } - MouseArea { - anchors.fill: parent - hoverEnabled: true - onClicked: cert.stopExam() - cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + + Tile { + anchors.horizontalCenter: undefined + width: parent.width * 0.48 + x: parent.width * 0.005 + y: parent.height * 0.99 - height + bgColor: Qt.tint(GLOB.wrongColor, NOO.alpha(activPal.base, 180)) + + bgBorder { + color: GLOB.wrongColor + width: 2 + } + + Column { + width: parent.width + + Text { + text: qsTr("Stop exam") + width: parent.width * 0.99 + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + + font { + pixelSize: width / 25 + bold: true + } + + } + + Image { + source: NOO.pix("stopExam") + height: parent.width / 12 + width: height * (sourceSize.width / sourceSize.height) + anchors.horizontalCenter: parent.horizontalCenter + } + + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + onClicked: cert.stopExam() + cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + } + } - } + } diff --git a/src/qml/exam/CorrectInstrAnim.qml b/src/qml/exam/CorrectInstrAnim.qml index 18a0e9e0df2c61aae0c5338ac21f85dee99de823..dc117b210c4fa9da695297ba0c16dead17cb1163 100644 --- a/src/qml/exam/CorrectInstrAnim.qml +++ b/src/qml/exam/CorrectInstrAnim.qml @@ -2,48 +2,156 @@ * Copyright (C) 2018 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 +import QtQuick 2.12 SequentialAnimation { - property bool doCross: false - property var wItem: instrItem.wrongItem - property real shakeStep: wItem ? Math.min(wItem.height, instrItem.height / 10) : instrItem.height / 10 - SequentialAnimation { // cross blinking - loops: doCross ? 2 : 0 - NumberAnimation { - property: "disp"; from: 0; to: 200; duration: 200 - target: Rectangle { - id: cross; parent: instrItem; visible: disp > 100; rotation: 45; z: 10 - property int disp: 0 - width: parent.height * 1.4; height: parent.height / 20; color: GLOB.wrongColor; anchors.centerIn: parent - Rectangle { height: parent.width; width: parent.height; color: GLOB.wrongColor; anchors.centerIn: parent } - } - } - NumberAnimation { target: cross; property: "disp"; from: 200; to: 0; duration: 200 } - } - SequentialAnimation { // shake - loops: doCross ? 0 : 2 - NumberAnimation { target: wItem; property: "y"; to: wItem ? wItem.y + shakeStep / 2 : 0; duration: 50 } - NumberAnimation { target: wItem; property: "y"; to: wItem ? wItem.y - shakeStep : 0; duration: 100 } - NumberAnimation { target: wItem; property: "y"; to: wItem ? wItem.y + shakeStep / 2 : 0; duration: 50 } - } - PauseAnimation { duration: 50 } - ParallelAnimation { - loops: wItem ? 1 : 0 - NumberAnimation { target: wItem; property: "opacity"; to: 0; duration: doCross ? 1 : 200 } - NumberAnimation { target: wItem; property: "scale"; to: 0.1; duration: doCross ? 1 : 200 } - } - ScriptAction { script: instrItem.applyCorrect() } - ParallelAnimation { - NumberAnimation { target: instrItem.goodItem; property: "opacity"; from: 0; to: 1; duration: 200 } // 5 is bandoneon - NumberAnimation { target: instrItem.goodItem; property: "scale"; from: 0.1; to: GLOB.instrument.type === 5 ? 1.2 : 1; duration: 200 } - } - SequentialAnimation { - NumberAnimation { target: instrItem.goodItem; property: "scale"; from: 1; to: GLOB.instrument.type === 5 ? 2.5 : 2; duration: 200 } - NumberAnimation { target: instrItem.goodItem; property: "scale"; from: 2; to: GLOB.instrument.type === 5 ? 1.2 : 1; duration: 200 } - } - ScriptAction { script: instrItem.finishCorrectAnim() } - onStopped: destroy() + property bool doCross: false + property var wItem: instrItem.wrongItem + property real shakeStep: wItem ? Math.min(wItem.height, instrItem.height / 10) : instrItem.height / 10 + + onStopped: destroy() + + // cross blinking + SequentialAnimation { + loops: doCross ? 2 : 0 + + NumberAnimation { + property: "disp" + from: 0 + to: 200 + duration: 200 + + target: Rectangle { + id: cross + + property int disp: 0 + + parent: instrItem + visible: disp > 100 + rotation: 45 + z: 10 + width: parent.height * 1.4 + height: parent.height / 20 + color: GLOB.wrongColor + anchors.centerIn: parent + + Rectangle { + height: parent.width + width: parent.height + color: GLOB.wrongColor + anchors.centerIn: parent + } + + } + + } + + NumberAnimation { + target: cross + property: "disp" + from: 200 + to: 0 + duration: 200 + } + + } + + // shake + SequentialAnimation { + loops: doCross ? 0 : 2 + + NumberAnimation { + target: wItem + property: "y" + to: wItem ? wItem.y + shakeStep / 2 : 0 + duration: 50 + } + + NumberAnimation { + target: wItem + property: "y" + to: wItem ? wItem.y - shakeStep : 0 + duration: 100 + } + + NumberAnimation { + target: wItem + property: "y" + to: wItem ? wItem.y + shakeStep / 2 : 0 + duration: 50 + } + + } + + PauseAnimation { + duration: 50 + } + + ParallelAnimation { + loops: wItem ? 1 : 0 + + NumberAnimation { + target: wItem + property: "opacity" + to: 0 + duration: doCross ? 1 : 200 + } + + NumberAnimation { + target: wItem + property: "scale" + to: 0.1 + duration: doCross ? 1 : 200 + } + + } + + ScriptAction { + script: instrItem.applyCorrect() + } + + ParallelAnimation { + // 5 is bandoneon + NumberAnimation { + target: instrItem.goodItem + property: "opacity" + from: 0 + to: 1 + duration: 200 + } + + NumberAnimation { + target: instrItem.goodItem + property: "scale" + from: 0.1 + to: GLOB.instrument.type === 5 ? 1.2 : 1 + duration: 200 + } + + } + + SequentialAnimation { + NumberAnimation { + target: instrItem.goodItem + property: "scale" + from: 1 + to: GLOB.instrument.type === 5 ? 2.5 : 2 + duration: 200 + } + + NumberAnimation { + target: instrItem.goodItem + property: "scale" + from: 2 + to: GLOB.instrument.type === 5 ? 1.2 : 1 + duration: 200 + } + + } + + ScriptAction { + script: instrItem.finishCorrectAnim() + } + } diff --git a/src/qml/exam/CorrectNameAnim.qml b/src/qml/exam/CorrectNameAnim.qml index d26b671116a6ab5bd687338472184d3b4c3e4551..f642f536d08d5d4ed33a860510c71046f3822517 100644 --- a/src/qml/exam/CorrectNameAnim.qml +++ b/src/qml/exam/CorrectNameAnim.qml @@ -2,41 +2,136 @@ * 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 Nootka 1.0 +import QtQuick 2.12 SequentialAnimation { - property bool doCross: false - SequentialAnimation { // cross blinking - loops: doCross ? 2 : 0 + property bool doCross: false + + // cross blinking + SequentialAnimation { + loops: doCross ? 2 : 0 + + NumberAnimation { + property: "disp" + from: 0 + to: 200 + duration: 200 + + target: Rectangle { + id: cross + + property int disp: 0 + + parent: textItem.parent + visible: disp > 100 + rotation: 45 + radius: height / 2 + width: parent.height * 1.4 + height: parent.height / 15 + color: GLOB.wrongColor + anchors.centerIn: parent + + Rectangle { + height: parent.width + width: parent.height + color: GLOB.wrongColor + anchors.centerIn: parent + radius: width + } + + } + + } + + NumberAnimation { + target: cross + property: "disp" + from: 200 + to: 0 + duration: 200 + } + + } + + // shake text + SequentialAnimation { + loops: doCross ? 0 : 2 + + NumberAnimation { + target: textItem.anchors + property: "horizontalCenterOffset" + to: textItem.height / 4 + duration: 50 + } + + NumberAnimation { + target: textItem.anchors + property: "horizontalCenterOffset" + to: -textItem.height / 4 + duration: 100 + } + + NumberAnimation { + target: textItem.anchors + property: "horizontalCenterOffset" + to: 0 + duration: 50 + } + + } + + PauseAnimation { + duration: 100 + } + + ParallelAnimation { + NumberAnimation { + target: textItem + property: "opacity" + to: 0 + duration: doCross ? 1 : 200 + } + + NumberAnimation { + target: textItem + property: "scale" + to: 2 + duration: doCross ? 1 : 200 + } + + } + + ScriptAction { + script: noteName.applyCorrect() + } + + ParallelAnimation { + NumberAnimation { + target: textItem + property: "opacity" + to: 1 + duration: 150 + } + + NumberAnimation { + target: textItem + property: "scale" + to: 6 + duration: 200 + } + + } + NumberAnimation { - property: "disp"; from: 0; to: 200; duration: 200 - target: Rectangle { - id: cross; parent: textItem.parent; visible: disp > 100; rotation: 45; radius: height / 2 - property int disp: 0 - width: parent.height * 1.4; height: parent.height / 15; color: GLOB.wrongColor; anchors.centerIn: parent - Rectangle { height: parent.width; width: parent.height; color: GLOB.wrongColor; anchors.centerIn: parent; radius: width } - } - } - NumberAnimation { target: cross; property: "disp"; from: 200; to: 0; duration: 200 } - } - SequentialAnimation { // shake text - loops: doCross ? 0 : 2 - NumberAnimation { target: textItem.anchors; property: "horizontalCenterOffset"; to: textItem.height / 4; duration: 50 } - NumberAnimation { target: textItem.anchors; property: "horizontalCenterOffset"; to: -textItem.height / 4; duration: 100 } - NumberAnimation { target: textItem.anchors; property: "horizontalCenterOffset"; to: 0; duration: 50 } - } - PauseAnimation { duration: 100 } - ParallelAnimation { - NumberAnimation { target: textItem; property: "opacity"; to: 0; duration: doCross ? 1 : 200 } - NumberAnimation { target: textItem; property: "scale"; to: 2; duration: doCross ? 1 : 200 } - } - ScriptAction { script: noteName.applyCorrect() } - ParallelAnimation { - NumberAnimation { target: textItem; property: "opacity"; to: 1; duration: 150 } - NumberAnimation { target: textItem; property: "scale"; to: 6; duration: 200 } - } - NumberAnimation { target: textItem; property: "scale"; to: 3; duration: 200 } - ScriptAction { script: noteName.finishCorrectAnim() } + target: textItem + property: "scale" + to: 3 + duration: 200 + } + + ScriptAction { + script: noteName.finishCorrectAnim() + } + } diff --git a/src/qml/exam/CorrectNoteAnim.qml b/src/qml/exam/CorrectNoteAnim.qml index 8834e232bc58bd6b2bc92a88a7885e5bc10a35e9..a2fbdfda9dc53448d643fe81d4ddf86a4949f553 100644 --- a/src/qml/exam/CorrectNoteAnim.qml +++ b/src/qml/exam/CorrectNoteAnim.qml @@ -2,47 +2,106 @@ * Copyright (C) 2019 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 +import QtQuick 2.12 SequentialAnimation { - property Item noteHead: null - property real endY: 0 - - signal applyCorrect() - - // private - property real halfY: 0 - - onRunningChanged: halfY = noteHead.y + (noteHead.y - endY) / 2 - - SequentialAnimation { // cross blinking when no note was selected - loops: noteHead && noteHead.parent.notePosY === 0 ? 2 : 0 - NumberAnimation { - property: "disp"; from: 0; to: 200; duration: 200 - target: Rectangle { - id: cross - parent: noteHead ? noteHead.parent : null; visible: disp > 100; rotation: 45; z: 10 - property int disp: 0 - width: parent ? parent.width * 2 : 0; height: width / 15; color: GLOB.wrongColor; anchors.centerIn: parent; radius: width / 4 - Rectangle { height: parent.width; width: parent.height; color: GLOB.wrongColor; anchors.centerIn: parent; radius: height / 4 } - } + property Item noteHead: null + property real endY: 0 + // private + property real halfY: 0 + + signal applyCorrect() + + onRunningChanged: halfY = noteHead.y + (noteHead.y - endY) / 2 + + // cross blinking when no note was selected + SequentialAnimation { + loops: noteHead && noteHead.parent.notePosY === 0 ? 2 : 0 + + NumberAnimation { + property: "disp" + from: 0 + to: 200 + duration: 200 + + target: Rectangle { + id: cross + + property int disp: 0 + + parent: noteHead ? noteHead.parent : null + visible: disp > 100 + rotation: 45 + z: 10 + width: parent ? parent.width * 2 : 0 + height: width / 15 + color: GLOB.wrongColor + anchors.centerIn: parent + radius: width / 4 + + Rectangle { + height: parent.width + width: parent.height + color: GLOB.wrongColor + anchors.centerIn: parent + radius: height / 4 + } + + } + + } + + NumberAnimation { + target: cross + property: "disp" + from: 200 + to: 0 + duration: 200 + } + + } + + ScriptAction { + script: noteHead.visible = true + } + + ParallelAnimation { + NumberAnimation { + target: noteHead + property: "y" + to: halfY + duration: 300 + } + + NumberAnimation { + target: noteHead + property: "scale" + to: 3 + duration: 300 + } + } - NumberAnimation { target: cross; property: "disp"; from: 200; to: 0; duration: 200 } - } - ScriptAction { script: noteHead.visible = true } + ScriptAction { + script: applyCorrect() + } + + ParallelAnimation { + NumberAnimation { + target: noteHead + property: "y" + to: endY + duration: 300 + } - ParallelAnimation { - NumberAnimation { target: noteHead; property: "y"; to: halfY; duration: 300 } - NumberAnimation { target: noteHead; property: "scale"; to: 3; duration: 300 } - } + NumberAnimation { + target: noteHead + property: "scale" + to: 1 + duration: 300 + } - ScriptAction { script: applyCorrect() } + } - ParallelAnimation { - NumberAnimation { target: noteHead; property: "y"; to: endY; duration: 300 } - NumberAnimation { target: noteHead; property: "scale"; to: 1; duration: 300 } - } } diff --git a/src/qml/exam/ExamExecutor.qml b/src/qml/exam/ExamExecutor.qml index 4400f680c91261829b41d5ce970dddfb1236e86e..8da9a3cba948b7441a3373eac9d906cb0179f8aa 100644 --- a/src/qml/exam/ExamExecutor.qml +++ b/src/qml/exam/ExamExecutor.qml @@ -2,98 +2,126 @@ * Copyright (C) 2017-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 Nootka 1.0 import Nootka.Exam 1.0 - -import "../" - +import QtQuick 2.12 Texecutor { - id: executor - - parent: NOO.isAndroid() ? nootkaWindow.contentItem : nootkaWindow.contentItem.parent - z: 100 - - //private - property var examSettDialog: null - property var helpGotIt: null - - anchors.fill: parent - - onTitleChanged: nootkaWindow.title = title + id: executor - onExamActionsChanged: { - if (!NOO.isAndroid()) - nootkaWindow.mainMenu.toolBar.examActions = examActions - } + //private + property var examSettDialog: null + property var helpGotIt: null - onExamSummary: nootkaWindow.showDialog(Nootka.ExamSummary) + parent: NOO.isAndroid() ? nootkaWindow.contentItem : nootkaWindow.contentItem.parent + z: 100 + anchors.fill: parent + onTitleChanged: nootkaWindow.title = title + onExamActionsChanged: { + if (!NOO.isAndroid()) + nootkaWindow.mainMenu.toolBar.examActions = examActions; - onShowSettings: { - if (!examSettDialog) { - examSettDialog = Qt.createComponent("qrc:/exam/ExamSettingsDialog.qml").createObject(executor, { "mode": isExercise ? 2 : 1 }) - examSettDialog.accepted.connect(settingsAccepted) - examSettDialog.closed.connect(function() { examSettDialog.destroy() }) } - } - - onWantMessage: { - var ms = Qt.createComponent("qrc:/Tmessage.qml").createObject(nootkaWindow.contentItem.parent, { "caption": caption, "message": message, "accent": accent }) - ms.closed.connect(afterMessage) - } - - onExecDiscarded: { - console.log("[ExamExecutor] Executor discarded, deleting it") - GLOB.isExam = false - nootkaWindow.executor.destroy() - } - - onShowHelp: { - if (!helpGotIt) - helpGotIt = Qt.createComponent("qrc:/gotit/ExamFlow.qml").createObject(executor, { "remaindChecked": showExamHelp }) - helpGotIt.open() - helpGotIt.closed.connect(afterMessage) - } - - onWantSuggestPopup: Qt.createComponent("qrc:/exam/TsuggestExam.qml").createObject(executor, { "entireVisible": showEntire }) - - Component.onDestruction: { - if (helpGotIt) - GLOB.setGotIt("examFlow", helpGotIt.remaindChecked) - } - - Connections { - target: tipHandler - onWantStartTip: { - var s = Qt.createComponent("qrc:/exam/ExamTip.qml") - tipHandler.startTip = s.createObject(executor, { "text": text, "offX": pos.x, "offY": pos.y, "bg": color } ) + onExamSummary: nootkaWindow.showDialog(Nootka.ExamSummary) + onShowSettings: { + if (!examSettDialog) { + examSettDialog = Qt.createComponent("qrc:/exam/ExamSettingsDialog.qml").createObject(executor, { + "mode": isExercise ? 2 : 1 + }); + examSettDialog.accepted.connect(settingsAccepted); + examSettDialog.closed.connect(function() { + examSettDialog.destroy(); + }); + } } - onWantQuestionTip: { - var s = Qt.createComponent("qrc:/exam/QuestionTip.qml") - tipHandler.questionTip = s.createObject(executor, { "text": text, "offX": pos.x, "offY": pos.y } ) + onWantMessage: { + var ms = Qt.createComponent("qrc:/Tmessage.qml").createObject(nootkaWindow.contentItem.parent, { + "caption": caption, + "message": message, + "accent": accent + }); + ms.closed.connect(afterMessage); } - onWantConfirmTip: { - var s = Qt.createComponent("qrc:/exam/ExamTip.qml") - tipHandler.confirmTip = s.createObject(executor, { "text": text, "offX": pos.x, "offY": pos.y, "bg": color, "showExit": !NOO.isAndroid() } ) + onExecDiscarded: { + console.log("[ExamExecutor] Executor discarded, deleting it"); + GLOB.isExam = false; + nootkaWindow.executor.destroy(); } - onWantResultTip: { - var r = Qt.createComponent("qrc:/exam/ResultTip.qml") - tipHandler.resultTip = r.createObject(executor.parent, { "text": text, "color": color } ) + onShowHelp: { + if (!helpGotIt) + helpGotIt = Qt.createComponent("qrc:/gotit/ExamFlow.qml").createObject(executor, { + "remaindChecked": showExamHelp + }); + + helpGotIt.open(); + helpGotIt.closed.connect(afterMessage); } - onWantTryAgainTip: { - var a = Qt.createComponent("qrc:/exam/ResultTip.qml") - tipHandler.tryAgainTip = a.createObject(executor.parent, { "text": qsTranslate("TtipHandler", "Try again!"), - "color": GLOB.wrongColor, "targetY": Math.min(executor.width, executor.height) / 12 } ) - } - onWantWhatNextTip: { - var s = Qt.createComponent("qrc:/exam/ExamTip.qml") - tipHandler.whatNextTip = s.createObject(executor, { "text": text, "offX": pos.x, "offY": pos.y, "bg": color } ) + onWantSuggestPopup: Qt.createComponent("qrc:/exam/TsuggestExam.qml").createObject(executor, { + "entireVisible": showEntire + }) + Component.onDestruction: { + if (helpGotIt) + GLOB.setGotIt("examFlow", helpGotIt.remaindChecked); + } - onWantCertificate: { - tipHandler.certTip = Qt.createComponent("qrc:/exam/Certificate.qml").createObject(nootkaWindow.contentItem.parent) + + Connections { + target: tipHandler + onWantStartTip: { + var s = Qt.createComponent("qrc:/exam/ExamTip.qml"); + tipHandler.startTip = s.createObject(executor, { + "text": text, + "offX": pos.x, + "offY": pos.y, + "bg": color + }); + } + onWantQuestionTip: { + var s = Qt.createComponent("qrc:/exam/QuestionTip.qml"); + tipHandler.questionTip = s.createObject(executor, { + "text": text, + "offX": pos.x, + "offY": pos.y + }); + } + onWantConfirmTip: { + var s = Qt.createComponent("qrc:/exam/ExamTip.qml"); + tipHandler.confirmTip = s.createObject(executor, { + "text": text, + "offX": pos.x, + "offY": pos.y, + "bg": color, + "showExit": !NOO.isAndroid() + }); + } + onWantResultTip: { + var r = Qt.createComponent("qrc:/exam/ResultTip.qml"); + tipHandler.resultTip = r.createObject(executor.parent, { + "text": text, + "color": color + }); + } + onWantTryAgainTip: { + var a = Qt.createComponent("qrc:/exam/ResultTip.qml"); + tipHandler.tryAgainTip = a.createObject(executor.parent, { + "text": qsTranslate("TtipHandler", "Try again!"), + "color": GLOB.wrongColor, + "targetY": Math.min(executor.width, executor.height) / 12 + }); + } + onWantWhatNextTip: { + var s = Qt.createComponent("qrc:/exam/ExamTip.qml"); + tipHandler.whatNextTip = s.createObject(executor, { + "text": text, + "offX": pos.x, + "offY": pos.y, + "bg": color + }); + } + onWantCertificate: { + tipHandler.certTip = Qt.createComponent("qrc:/exam/Certificate.qml").createObject(nootkaWindow.contentItem.parent); + } } - } -} +} diff --git a/src/qml/exam/ExamResults.qml b/src/qml/exam/ExamResults.qml index 7fdc61016c53a3d5b1c83cfbb3c818e2606aafe9..c6816e804d11dc3280d7240a54ea24285832f6e2 100644 --- a/src/qml/exam/ExamResults.qml +++ b/src/qml/exam/ExamResults.qml @@ -2,218 +2,335 @@ * 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 Nootka.Exam 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 -import Nootka.Exam 1.0 -import "../" +Grid { + id: resultsItem + function more(sender) { + popLoader.sourceComponent = popComp; + popLoader.item.open(); + popLoader.item.senderIndex = sender.index; + } -Grid { - id: resultsItem - columns: 2 - width: parent.width - height: visible ? nootkaWindow.width / 45 : 0 - y: 1; z: 5 - verticalItemAlignment: Grid.AlignVCenter; horizontalItemAlignment: Grid.AlignHCenter - - visible: !results.isExercise - - Tresults { id: results } - - Row { - spacing: NOO.factor() - width: resultsItem.width / 2; leftPadding: (width - childrenRect.width) / 2 - ResultLabel { - index: 1 - width: height * 4 - score: results.answersText - onGetTip: showTip(results.answersHint()) - hi: popLoader.item && popLoader.item.senderIndex === index + columns: 2 + width: parent.width + height: visible ? nootkaWindow.width / 45 : 0 + y: 1 + z: 5 + verticalItemAlignment: Grid.AlignVCenter + horizontalItemAlignment: Grid.AlignHCenter + visible: !results.isExercise + + Tresults { + id: results } - ProgressBar { - id: control - property int index: 2 - anchors.verticalCenter: parent.verticalCenter - width: resultsItem.width / 5; height: nootkaWindow.width / 70 - from: 0; to: results.progressMax - value: results.progressValue - hoverEnabled: !NOO.isAndroid() - - onHoveredChanged: { - if (GLOB.showHints) { - if (hovered) - NOO.setStatusTip(results.progressHint(), Item.Top) - else - NOO.setStatusTip("", Item.Top) + + Row { + spacing: NOO.factor() + width: resultsItem.width / 2 + leftPadding: (width - childrenRect.width) / 2 + + ResultLabel { + index: 1 + width: height * 4 + score: results.answersText + onGetTip: showTip(results.answersHint()) + hi: popLoader.item && popLoader.item.senderIndex === index } - } - - background: Rectangle { // can not be null to handle mouse click/tap - width: control.width; height: control.height * 0.8; y: control.height * 0.1 - color: "transparent" - } - - contentItem: Item { - width: control.width; height: control.height * 0.8; y: control.height * 0.1 - Row { - anchors.horizontalCenter: parent.horizontalCenter - Repeater { - model: control.width / (control.height / 2.63) // 2.63 is '!' glyph factor - Text { - font { family: "Nootka"; pixelSize: control.height } - text: "!" - color: x < control.position * control.width ? GLOB.correctColor : GLOB.wrongColor - scale: x < control.position * control.width ? 1 : 0.8 - Behavior on color { enabled: GLOB.useAnimations; ColorAnimation { duration: 1000 } } - Behavior on scale { enabled: GLOB.useAnimations; PropertyAnimation { duration: 1000 } } + + ProgressBar { + id: control + + property int index: 2 + + anchors.verticalCenter: parent.verticalCenter + width: resultsItem.width / 5 + height: nootkaWindow.width / 70 + from: 0 + to: results.progressMax + value: results.progressValue + hoverEnabled: !NOO.isAndroid() + onHoveredChanged: { + if (GLOB.showHints) { + if (hovered) + NOO.setStatusTip(results.progressHint(), Item.Top); + else + NOO.setStatusTip("", Item.Top); + } + } + + MouseArea { + anchors.fill: parent.background + onClicked: resultsItem.more(parent) + } + + // can not be null to handle mouse click/tap + background: Rectangle { + width: control.width + height: control.height * 0.8 + y: control.height * 0.1 + color: "transparent" + } + + contentItem: Item { + width: control.width + height: control.height * 0.8 + y: control.height * 0.1 + + Row { + anchors.horizontalCenter: parent.horizontalCenter + + Repeater { + model: control.width / (control.height / 2.63) // 2.63 is '!' glyph factor + + Text { + text: "!" + color: x < control.position * control.width ? GLOB.correctColor : GLOB.wrongColor + scale: x < control.position * control.width ? 1 : 0.8 + + font { + family: "Nootka" + pixelSize: control.height + } + + Behavior on color { + enabled: GLOB.useAnimations + + ColorAnimation { + duration: 1000 + } + + } + + Behavior on scale { + enabled: GLOB.useAnimations + + PropertyAnimation { + duration: 1000 + } + + } + + } + + } + + } + + Rectangle { + id: percentRect + + width: percentText.width + height: control.height + anchors.centerIn: parent + color: activPal.window + opacity: control.hovered ? 1 : 0 + + Text { + id: percentText + + anchors.centerIn: parent + font.pointSize: percentRect.height * 0.8 + text: " " + Math.round(control.position * 100) + " % " + } + + Behavior on opacity { + enabled: GLOB.useAnimations + + PropertyAnimation { + } + + } + + } + } - } + } - Rectangle { - id: percentRect - width: percentText.width; height: control.height - anchors.centerIn: parent - color: activPal.window - opacity: control.hovered ? 1 : 0 - Behavior on opacity { enabled: GLOB.useAnimations; PropertyAnimation {} } - Text { - id: percentText - anchors.centerIn: parent - font.pointSize: percentRect.height * 0.8 - text: " " + Math.round(control.position * 100) + " % " - } + + ResultLabel { + index: 3 + width: height * 4 + score: results.totalText + onGetTip: showTip(results.summaryHint()) + hi: popLoader.item && popLoader.item.senderIndex === index } - } - MouseArea { - anchors.fill: parent.background - onClicked: resultsItem.more(parent) - } - } - ResultLabel { - index: 3 - width: height * 4 - score: results.totalText - onGetTip: showTip(results.summaryHint()) - hi: popLoader.item && popLoader.item.senderIndex === index - } - } - - Row { - width: resultsItem.width / 2; leftPadding: (width - childrenRect.width) / 2 - spacing: NOO.factor() / 2 - - ResultLabel { - index: 4 - score: results.correctAnswers - onGetTip: showTip(results.correctHint()) - bg: GLOB.correctColor - hi: popLoader.item && popLoader.item.senderIndex === index - } - ResultLabel { - index: 5 - score: results.halfAnswers - onGetTip: showTip(results.halfHint()) - bg: GLOB.notBadColor - hi: popLoader.item && popLoader.item.senderIndex === index - } - ResultLabel { - index: 6 - score: results.wrongAnswers - onGetTip: showTip(results.wrongHint()) - bg: GLOB.wrongColor - hi: popLoader.item && popLoader.item.senderIndex === index } - ResultLabel { - index: 7 - width: height * 4 - score: results.effectiveness - onGetTip: showTip(results.effectHint()) - hi: popLoader.item && popLoader.item.senderIndex === index - } - ResultLabel { - index: 8 - width: height * 2.5 - score: results.averText - onGetTip: showTip(results.averageHint()) - hi: popLoader.item && popLoader.item.senderIndex === index - } - ResultLabel { - index: 9 - width: height * 2.5 - score: results.reactText - onGetTip: showTip(results.answerTimeTxt()) - hi: popLoader.item && popLoader.item.senderIndex === index - } - ResultLabel { - index: 10 - width: height * 3 - score: results.totalTimeText - onGetTip: showTip(results.examTimeTxt()) - hi: popLoader.item && popLoader.item.senderIndex === index - } - } - - Loader { id: popLoader } - Component { - id: popComp - Popup { - id: resPop - property int senderIndex: -1 - x: (nootkaWindow.width - width) / 2 - scale: 0 - enter: Transition { enabled: GLOB.useAnimations; SpringAnimation { property: "scale"; to: 1; spring: 2; damping: 0.2; epsilon: 0.005 }} - exit: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; from: 1; to: 0 }} // duration 250 ms - background: GlowRect { color: activPal.button; shadowRadius: NOO.factor() / 2 } - y: resultsItem.height + NOO.factor() / 2 - Column { - spacing: NOO.factor() / 6 - Repeater { - model: [ results.resultsTxt(), results.answersHint(), results.progressHint(), results.summaryHint(), results.correctHint(), - results.halfHint(), results.wrongHint(), results.effectHint(), results.averageHint() ] - Text { - text: modelData - color: resPop.senderIndex === index ? activPal.highlightedText : activPal.text - font { bold: index === 0; pixelSize: nootkaWindow.height / 30 } - Rectangle { - z: -1 - color: resPop.senderIndex === index ? activPal.highlight : (index % 2 === 1 ? activPal.alternateBase : activPal.base) - width: resPop.contentWidth; height: parent.height - } - } + Row { + width: resultsItem.width / 2 + leftPadding: (width - childrenRect.width) / 2 + spacing: NOO.factor() / 2 + + ResultLabel { + index: 4 + score: results.correctAnswers + onGetTip: showTip(results.correctHint()) + bg: GLOB.correctColor + hi: popLoader.item && popLoader.item.senderIndex === index } - Text { - text: results.answerTimeTxt() + ": <b>" + results.reactText + "</b>" - color: resPop.senderIndex === 9 ? activPal.highlightedText : activPal.text - font.pixelSize: nootkaWindow.height / 30 - Rectangle { - z: -1 - color: resPop.senderIndex === 9 ? activPal.highlight : activPal.alternateBase - width: resPop.contentWidth; height: parent.height - } + + ResultLabel { + index: 5 + score: results.halfAnswers + onGetTip: showTip(results.halfHint()) + bg: GLOB.notBadColor + hi: popLoader.item && popLoader.item.senderIndex === index } - Text { - text: results.examTimeTxt() + ": <b>" + results.totalTimeText + "</b>" - color: resPop.senderIndex === 10 ? activPal.highlightedText : activPal.text - font.pixelSize: nootkaWindow.height / 30 - Rectangle { - z: -1 - color: resPop.senderIndex === 10 ? activPal.highlight : activPal.base - width: resPop.contentWidth; height: parent.height - } + + ResultLabel { + index: 6 + score: results.wrongAnswers + onGetTip: showTip(results.wrongHint()) + bg: GLOB.wrongColor + hi: popLoader.item && popLoader.item.senderIndex === index + } + + ResultLabel { + index: 7 + width: height * 4 + score: results.effectiveness + onGetTip: showTip(results.effectHint()) + hi: popLoader.item && popLoader.item.senderIndex === index + } + + ResultLabel { + index: 8 + width: height * 2.5 + score: results.averText + onGetTip: showTip(results.averageHint()) + hi: popLoader.item && popLoader.item.senderIndex === index + } + + ResultLabel { + index: 9 + width: height * 2.5 + score: results.reactText + onGetTip: showTip(results.answerTimeTxt()) + hi: popLoader.item && popLoader.item.senderIndex === index } - } - onClosed: popLoader.sourceComponent = null + + ResultLabel { + index: 10 + width: height * 3 + score: results.totalTimeText + onGetTip: showTip(results.examTimeTxt()) + hi: popLoader.item && popLoader.item.senderIndex === index + } + } - } - function more(sender) { - popLoader.sourceComponent = popComp - popLoader.item.open() - popLoader.item.senderIndex = sender.index - } + Loader { + id: popLoader + } + + Component { + id: popComp + + Popup { + id: resPop + + property int senderIndex: -1 + + x: (nootkaWindow.width - width) / 2 + scale: 0 + y: resultsItem.height + NOO.factor() / 2 + onClosed: popLoader.sourceComponent = null + + Column { + spacing: NOO.factor() / 6 + + Repeater { + model: [results.resultsTxt(), results.answersHint(), results.progressHint(), results.summaryHint(), results.correctHint(), results.halfHint(), results.wrongHint(), results.effectHint(), results.averageHint()] + + Text { + text: modelData + color: resPop.senderIndex === index ? activPal.highlightedText : activPal.text + + font { + bold: index === 0 + pixelSize: nootkaWindow.height / 30 + } + + Rectangle { + z: -1 + color: resPop.senderIndex === index ? activPal.highlight : (index % 2 === 1 ? activPal.alternateBase : activPal.base) + width: resPop.contentWidth + height: parent.height + } + + } + + } + + Text { + text: results.answerTimeTxt() + ": <b>" + results.reactText + "</b>" + color: resPop.senderIndex === 9 ? activPal.highlightedText : activPal.text + font.pixelSize: nootkaWindow.height / 30 + + Rectangle { + z: -1 + color: resPop.senderIndex === 9 ? activPal.highlight : activPal.alternateBase + width: resPop.contentWidth + height: parent.height + } + + } + + Text { + text: results.examTimeTxt() + ": <b>" + results.totalTimeText + "</b>" + color: resPop.senderIndex === 10 ? activPal.highlightedText : activPal.text + font.pixelSize: nootkaWindow.height / 30 + + Rectangle { + z: -1 + color: resPop.senderIndex === 10 ? activPal.highlight : activPal.base + width: resPop.contentWidth + height: parent.height + } + + } + + } + + enter: Transition { + enabled: GLOB.useAnimations + + SpringAnimation { + property: "scale" + to: 1 + spring: 2 + damping: 0.2 + epsilon: 0.005 + } + + } + // duration 250 ms + + exit: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + from: 1 + to: 0 + } + + } + + background: GlowRect { + color: activPal.button + shadowRadius: NOO.factor() / 2 + } + + } + + } } diff --git a/src/qml/exam/ExamSettingsDialog.qml b/src/qml/exam/ExamSettingsDialog.qml index b8932ed4918ab28e0d6efae34e84a7d448d36ad8..654ce850e239ff8f7f891f647fbdfd133fb7931e 100644 --- a/src/qml/exam/ExamSettingsDialog.qml +++ b/src/qml/exam/ExamSettingsDialog.qml @@ -2,27 +2,26 @@ * 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 Nootka 1.0 import "../" import "../settings" - +import Nootka 1.0 +import QtQuick 2.12 TpopupDialog { - id: examSettDialog - property alias mode: examPage.mode - visible: true + id: examSettDialog + + property alias mode: examPage.mode - width: parent.width * (NOO.isAndroid() ? 0.95 : 0.8) - height: parent.height * (NOO.isAndroid() ? 0.95 : 0.8) + visible: true + width: parent.width * (NOO.isAndroid() ? 0.95 : 0.8) + height: parent.height * (NOO.isAndroid() ? 0.95 : 0.8) + caption: qsTranslate("TsettingsDialog", "Simple exam settings") + onAccepted: examPage.save() - caption: qsTranslate("TsettingsDialog", "Simple exam settings") + ExamPage { + id: examPage - ExamPage { - id: examPage - height: parent.height - } + height: parent.height + } - onAccepted: examPage.save() } diff --git a/src/qml/exam/ExamSummary.qml b/src/qml/exam/ExamSummary.qml index 750658c7f219cf024e62a99fb2144dccf1f59819..f2a50f1ce3189f5a59f5068088d5b59c8d5a67fc 100644 --- a/src/qml/exam/ExamSummary.qml +++ b/src/qml/exam/ExamSummary.qml @@ -2,225 +2,328 @@ * 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 QtQuick.Controls 2.12 -import Qt5Compat.GraphicalEffects - +import "../" +import "../level" import Nootka 1.0 import Nootka.Exam 1.0 -import "../level" -import "../" - +import Qt5Compat.GraphicalEffects +import QtQuick 2.12 +import QtQuick.Controls 2.12 TexamSummary { - id: summDialog - width: parent.width; height: parent.height - levelPreview: previewItem + id: summDialog - Column { width: parent.width - spacing: NOO.factor() / 2 - - Tflickable { - width: parent.width; height: summDialog.height - buttGrid.height - NOO.factor() - clip: true - contentWidth: width; contentHeight: resGrid.height - Grid { - id: resGrid - columns: summDialog.width > NOO.factor() * 50 ? 2 : 1 + height: parent.height + levelPreview: previewItem + Component.onCompleted: { + dialLoader.standardButtons = 0; + dialLoader.title = summDialog.title(); + } + Component.onDestruction: { + if (discardedAtBegin()) { + nootkaWindow.executor.destroy(); + GLOB.isExam = false; + } else { + closeSummary(); + } + } + + Column { + width: parent.width spacing: NOO.factor() / 2 - anchors.horizontalCenter: parent.horizontalCenter - Column { - width: summDialog.width / resGrid.columns - NOO.factor() / 2 - Text { // student - anchors.horizontalCenter: parent.horizontalCenter - text: student; textFormat: Text.StyledText - } - Item { width: NOO.factor(); height: NOO.factor() } - Tile { // answers/mistakes numbers + Tflickable { width: parent.width + height: summDialog.height - buttGrid.height - NOO.factor() + clip: true + contentWidth: width + contentHeight: resGrid.height + Grid { - anchors.horizontalCenter: parent.horizontalCenter - columns: NOO.isAndroid() || parent.width < NOO.factor() * 50 ? 1 : 2 - horizontalItemAlignment: Grid.AlignHCenter; verticalItemAlignment: Grid.AlignVCenter - spacing: NOO.factor() * (NOO.isAndroid() ? 1 : 2) - Column { - spacing: NOO.factor() - Text { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - text: resultHeader; textFormat: Text.StyledText - font.pixelSize: NOO.factor() * 1.3 - } - Grid { - columns: 2; columnSpacing: NOO.factor() - Repeater { - model: answersLabel + id: resGrid + + columns: summDialog.width > NOO.factor() * 50 ? 2 : 1 + spacing: NOO.factor() / 2 + anchors.horizontalCenter: parent.horizontalCenter + + Column { + width: summDialog.width / resGrid.columns - NOO.factor() / 2 + + // student Text { - text: modelData - color: activPal.text; textFormat: Text.StyledText - font.pixelSize: NOO.factor() * 1.2 + anchors.horizontalCenter: parent.horizontalCenter + text: student + textFormat: Text.StyledText } - } - } - } - Item { - width: NOO.factor() * (NOO.isAndroid() ? 15 : 20); height: width + NOO.factor() - visible: hasQuestions - TpieChartItem { - id: answId - width: parent.width; height: width - values: answersModel - colors: [ cn(GLOB.correctColor), cn(GLOB.notBadColor), cn(GLOB.wrongColor) ] + + Item { + width: NOO.factor() + height: NOO.factor() + } + // answers/mistakes numbers + + Tile { + width: parent.width + + Grid { + anchors.horizontalCenter: parent.horizontalCenter + columns: NOO.isAndroid() || parent.width < NOO.factor() * 50 ? 1 : 2 + horizontalItemAlignment: Grid.AlignHCenter + verticalItemAlignment: Grid.AlignVCenter + spacing: NOO.factor() * (NOO.isAndroid() ? 1 : 2) + + Column { + spacing: NOO.factor() + + Text { + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + text: resultHeader + textFormat: Text.StyledText + font.pixelSize: NOO.factor() * 1.3 + } + + Grid { + columns: 2 + columnSpacing: NOO.factor() + + Repeater { + model: answersLabel + + Text { + text: modelData + color: activPal.text + textFormat: Text.StyledText + font.pixelSize: NOO.factor() * 1.2 + } + + } + + } + + } + + Item { + width: NOO.factor() * (NOO.isAndroid() ? 15 : 20) + height: width + NOO.factor() + visible: hasQuestions + + TpieChartItem { + id: answId + + width: parent.width + height: width + values: answersModel + colors: [cn(GLOB.correctColor), cn(GLOB.notBadColor), cn(GLOB.wrongColor)] + } + + DropShadow { + anchors.fill: answId + horizontalOffset: NOO.factor() / 2 + verticalOffset: NOO.factor() / 2 + radius: NOO.factor() + samples: 1 + radius * 2 + color: activPal.shadow + source: answId + } + + } + + } + + } + // results + + Tile { + width: parent.width + visible: resultsModel.length + + Grid { + anchors.horizontalCenter: parent.horizontalCenter + columns: NOO.isAndroid() || parent.width < NOO.factor() * 50 ? 1 : 2 + horizontalItemAlignment: Grid.AlignHCenter + verticalItemAlignment: Grid.AlignVCenter + spacing: NOO.factor() * (NOO.isAndroid() ? 1 : 2) + + Column { + spacing: NOO.factor() + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: qsTranslate("TexamSummary", "Kinds of mistakes") + ":" + color: activPal.text + } + + Grid { + columns: 2 + columnSpacing: NOO.factor() + + Repeater { + model: resultsModel + + Text { + text: modelData + color: activPal.text + textFormat: Text.StyledText + } + + } + + } + + } + + Item { + visible: hasVariousMistakes + width: NOO.factor() * (NOO.isAndroid() ? 15 : 20) + height: width + NOO.factor() + + TpieChartItem { + id: pie + + width: parent.width + height: width + values: summDialog.kindOfMistakes + colors: [cn(GLOB.wrongColor)] + } + + DropShadow { + anchors.fill: pie + horizontalOffset: NOO.factor() / 2 + verticalOffset: NOO.factor() / 2 + radius: NOO.factor() + samples: 1 + radius * 2 + color: activPal.shadow + source: pie + } + + } + + } + + } + } - DropShadow { - anchors.fill: answId - horizontalOffset: NOO.factor() / 2; verticalOffset: NOO.factor() / 2 - radius: NOO.factor() - samples: 1 + radius * 2; color: activPal.shadow - source: answId + + Column { + width: summDialog.width / resGrid.columns - NOO.factor() / 2 + + // times + Tile { + id: timeTile + + width: parent.width + + Column { + spacing: NOO.factor() + width: parent.width + + Text { + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + text: qsTranslate("TexamSummary", "times:") + font.pixelSize: NOO.factor() * 1.1 + } + + Grid { + anchors.horizontalCenter: parent.horizontalCenter + columns: 2 + columnSpacing: NOO.factor() + + Repeater { + model: timesModel + + Text { + text: modelData + color: activPal.text + textFormat: Text.StyledText + } + + } + + } + + } + + } + + LevelPreview { + id: previewItem + + width: parent.width + height: resGrid.columns === 2 ? summDialog.height - buttGrid.height - NOO.factor() - timeTile.height : summDialog.height / 2 + } + } - } + // resGrid + } - } - Tile { // results - width: parent.width - visible: resultsModel.length - Grid { - anchors.horizontalCenter: parent.horizontalCenter - columns: NOO.isAndroid() || parent.width < NOO.factor() * 50 ? 1 : 2 - horizontalItemAlignment: Grid.AlignHCenter; verticalItemAlignment: Grid.AlignVCenter - spacing: NOO.factor() * (NOO.isAndroid() ? 1 : 2) - Column { - spacing: NOO.factor() - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: qsTranslate("TexamSummary", "Kinds of mistakes") + ":"; color: activPal.text + // Tflickable + + } + + Grid { + id: buttGrid + + property real buttWidth: buttColumsCount() === 2 ? summDialog.width / 3 : summDialog.width / 4 + property real buttHeight: Math.min(summDialog.width, summDialog.height) / 15 + + anchors.horizontalCenter: parent.horizontalCenter + spacing: summDialog.width / 100 + columns: buttColumsCount() + + TiconButton { + visible: enableContinue() + width: buttGrid.buttWidth + pixmap: NOO.pix(isExercise() ? "practice" : "exam") + iconHeight: buttGrid.buttHeight + text: NOO.TR("QWizard", "Continue") + onClicked: { + continueExecutor(); + dialLoader.close(); } - Grid { - columns: 2; columnSpacing: NOO.factor() - Repeater { - model: resultsModel - Text { - text: modelData - color: activPal.text; textFormat: Text.StyledText + } + + TiconButton { + visible: hasQuestions && (!NOO.isAndroid() || !isExercise()) + width: buttGrid.buttWidth + pixmap: NOO.pix(NOO.isAndroid() ? "send" : "charts") + iconHeight: buttGrid.buttHeight + text: NOO.isAndroid() ? NOO.TR("QShortcut", "Send") : qsTr("Analyze") + onClicked: { + if (NOO.isAndroid()) { + sendExam(); + } else { + nootkaWindow.showDialog(6); // 6 - Nootka.Charts + nootkaWindow.analyzeWindow.allowOpen = false; + nootkaWindow.analyzeWindow.exam = summDialog.exam(); } - } - } - } - Item { - visible: hasVariousMistakes - width: NOO.factor() * (NOO.isAndroid() ? 15 : 20); height: width + NOO.factor() - TpieChartItem { - id: pie - width: parent.width; height: width - values: summDialog.kindOfMistakes - colors: [ cn(GLOB.wrongColor) ] - } - DropShadow { - anchors.fill: pie - horizontalOffset: NOO.factor() / 2; verticalOffset: NOO.factor() / 2 - radius: NOO.factor() - samples: 1 + radius * 2; color: activPal.shadow - source: pie } - } } - } - } - Column { - width: summDialog.width / resGrid.columns - NOO.factor() / 2 - Tile { // times - id: timeTile - width: parent.width - Column { - spacing: NOO.factor() - width: parent.width - Text { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - text: qsTranslate("TexamSummary", "times:") - font.pixelSize: NOO.factor() * 1.1 - } - Grid { - anchors.horizontalCenter: parent.horizontalCenter - columns: 2; columnSpacing: NOO.factor() - Repeater { - model: timesModel - Text { - text: modelData - color: activPal.text; textFormat: Text.StyledText - } + TiconButton { + visible: isExercise() + width: buttGrid.buttWidth + pixmap: NOO.pix("exam") + iconHeight: buttGrid.buttHeight + text: qsTr("Pass an exam") + onClicked: { + exerciseToExam(); + dialLoader.close(); } - } } - } - LevelPreview { - id: previewItem - width: parent.width - height: resGrid.columns === 2 ? summDialog.height - buttGrid.height - NOO.factor() - timeTile.height : summDialog.height / 2 - } - } - } // resGrid - } // Tflickable - - Grid { - id: buttGrid - anchors.horizontalCenter: parent.horizontalCenter - spacing: summDialog.width / 100 - columns: buttColumsCount() - property real buttWidth: buttColumsCount() === 2 ? summDialog.width / 3 : summDialog.width / 4 - property real buttHeight: Math.min(summDialog.width, summDialog.height) / 15 - TiconButton { - visible: enableContinue() - width: buttGrid.buttWidth - pixmap: NOO.pix(isExercise() ? "practice" : "exam"); iconHeight: buttGrid.buttHeight - text: NOO.TR("QWizard", "Continue") - onClicked: { continueExecutor(); dialLoader.close() } - } - TiconButton { - visible: hasQuestions && (!NOO.isAndroid() || !isExercise()) - width: buttGrid.buttWidth - pixmap: NOO.pix(NOO.isAndroid() ? "send" : "charts"); iconHeight: buttGrid.buttHeight - text: NOO.isAndroid() ? NOO.TR("QShortcut", "Send") : qsTr("Analyze") - onClicked: { - if (NOO.isAndroid()) { - sendExam() - } else { - nootkaWindow.showDialog(6) // 6 - Nootka.Charts - nootkaWindow.analyzeWindow.allowOpen = false - nootkaWindow.analyzeWindow.exam = summDialog.exam() + + TiconButton { + width: buttGrid.buttWidth + pixmap: NOO.pix("exit") + iconHeight: buttGrid.buttHeight + text: NOO.TR("QPlatformTheme", "Close") + onClicked: dialLoader.close() } - } - } - TiconButton { - visible: isExercise() - width: buttGrid.buttWidth - pixmap: NOO.pix("exam"); iconHeight: buttGrid.buttHeight - text: qsTr("Pass an exam") - onClicked: { exerciseToExam(); dialLoader.close() } - } - TiconButton { - width: buttGrid.buttWidth - pixmap: NOO.pix("exit"); iconHeight: buttGrid.buttHeight - text: NOO.TR("QPlatformTheme", "Close") - onClicked: dialLoader.close() + } + } - } - - Component.onCompleted: { - dialLoader.standardButtons = 0 - dialLoader.title = summDialog.title() - } - - Component.onDestruction: { - if (discardedAtBegin()) { - nootkaWindow.executor.destroy() - GLOB.isExam = false - } else - closeSummary() - } + } diff --git a/src/qml/exam/ExamTip.qml b/src/qml/exam/ExamTip.qml index d773551045ff1d47bbeaa4434a438ee139710ec3..31767649fd873d56a22517ff1c8a64424473cf22 100644 --- a/src/qml/exam/ExamTip.qml +++ b/src/qml/exam/ExamTip.qml @@ -2,85 +2,108 @@ * 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.Window 2.12 -import Nootka 1.0 -import "../" +GlowRect { + id: tip + property alias text: text.text + property alias textItem: text + property alias font: text.font + property color bg: activPal.base + property real offX: 0 + property real offY: 0 + property alias showExit: exitImg.visible + // private + property real eW: 0 + property real eH: 0 + + color: Qt.tint(activPal.base, NOO.alpha(bg, 50)) + shadowRadius: NOO.factor() * 2 + radius: NOO.factor() + cornerRadius: NOO.factor() * 2 + z: 200 + x: NOO.bound(NOO.factor(), offX - width / 2, executor.width - width - NOO.factor()) + y: NOO.bound(NOO.factor(), offY - height / 2, executor.height - height - NOO.factor()) + width: text.width + height: text.height + scale: GLOB.useAnimations ? 0 : 1 + Component.onCompleted: { + eW = executor.width; + eH = executor.height; + if (GLOB.useAnimations) + scale = 1; -GlowRect { - id: tip - - property alias text: text.text - property alias textItem: text - property alias font: text.font - property color bg: activPal.base - property real offX: 0 - property real offY: 0 - property alias showExit: exitImg.visible - - // private - property real eW: 0 - property real eH: 0 - - color: Qt.tint(activPal.base, NOO.alpha(bg, 50)) - border { width: NOO.factor() / 6; color: bg } - shadowRadius: NOO.factor() * 2 - radius: NOO.factor() - cornerRadius: NOO.factor() * 2 - z: 200 - x: NOO.bound(NOO.factor(), offX - width / 2, executor.width - width - NOO.factor()) - y: NOO.bound(NOO.factor(), offY - height / 2, executor.height - height - NOO.factor()) - width: text.width; height: text.height - scale: GLOB.useAnimations ? 0 : 1 - - Text { - id: text - color: activPal.text - textFormat: Text.RichText - padding: NOO.factor() - onLinkActivated: { - executor.tipLink(link) - tip.destroy() } - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + + border { + width: NOO.factor() / 6 + color: bg } - } - - Image { - id: exitImg - visible: false - anchors { right: parent.right; top: parent.top; margins: tip.width / 80 } - source: NOO.pix("exit") - sourceSize.width: tip.width / 20 - MouseArea { - anchors.fill: parent - onClicked: tip.visible = false + + Text { + id: text + + color: activPal.text + textFormat: Text.RichText + padding: NOO.factor() + onLinkActivated: { + executor.tipLink(link); + tip.destroy(); + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } + + } + + Image { + id: exitImg + + visible: false + source: NOO.pix("exit") + sourceSize.width: tip.width / 20 + + anchors { + right: parent.right + top: parent.top + margins: tip.width / 80 + } + + MouseArea { + anchors.fill: parent + onClicked: tip.visible = false + } + } - } - - Component.onCompleted: { - eW = executor.width; eH = executor.height - if (GLOB.useAnimations) - scale = 1.0 - } - - Connections { - target: executor - onWidthChanged: { - scale = (executor.width / eW) * scale - offX = offX * (executor.width / eW) - eW = executor.width + + Connections { + target: executor + onWidthChanged: { + scale = (executor.width / eW) * scale; + offX = offX * (executor.width / eW); + eW = executor.width; + } + onHeightChanged: { + offY = offY * (executor.height / eH); + eH = executor.height; + } } - onHeightChanged: { - offY = offY *(executor.height / eH) - eH = executor.height + + Behavior on scale { + SpringAnimation { + spring: 2 + damping: 0.2 + epsilon: 0.005 + duration: 300 + } + } - } - Behavior on scale { SpringAnimation { spring: 2; damping: 0.2; epsilon: 0.005; duration: 300 }} } diff --git a/src/qml/exam/QuestionTip.qml b/src/qml/exam/QuestionTip.qml index b73894f287c18da24a34c286eeb8428ccd4b1883..a1ec08e89f74af98baa6886458bc9d54a89758bb 100644 --- a/src/qml/exam/QuestionTip.qml +++ b/src/qml/exam/QuestionTip.qml @@ -2,41 +2,61 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 +import QtQuick 2.12 ExamTip { - id: examTip - - bg: GLOB.wrongColor - font.pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.25) - width: textItem.width + height / 2 - textItem.z: 1 // above question mark - - Text { - font { pixelSize: examTip.height; family: "Nootka" } - x: examTip.width - width * 0.95 - text: "?"; color: Qt.tint(activPal.base, NOO.alpha(GLOB.wrongColor, 70)) - } - - MouseArea { - id: dragArea - anchors.fill: parent - z: 2 // above all context - hoverEnabled: true - drag.target: parent - drag.smoothed: false - drag.minimumX: NOO.factor(); drag.maximumX: executor.width - width * scale - NOO.factor() - drag.minimumY: NOO.factor(); drag.maximumY: executor.height - height * scale - NOO.factor() - cursorShape: drag.active ? Qt.DragMoveCursor : (containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor) - } - - Component.onCompleted: { - if (GLOB.useAnimations) - rotation = 720 - } - - Behavior on scale { NumberAnimation { duration: 500 }} - Behavior on rotation { NumberAnimation { duration: 500 }} + id: examTip + + bg: GLOB.wrongColor + font.pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.25) + width: textItem.width + height / 2 + textItem.z: 1 // above question mark + Component.onCompleted: { + if (GLOB.useAnimations) + rotation = 720; + + } + + Text { + x: examTip.width - width * 0.95 + text: "?" + color: Qt.tint(activPal.base, NOO.alpha(GLOB.wrongColor, 70)) + + font { + pixelSize: examTip.height + family: "Nootka" + } + + } + + MouseArea { + id: dragArea + + anchors.fill: parent + z: 2 // above all context + hoverEnabled: true + drag.target: parent + drag.smoothed: false + drag.minimumX: NOO.factor() + drag.maximumX: executor.width - width * scale - NOO.factor() + drag.minimumY: NOO.factor() + drag.maximumY: executor.height - height * scale - NOO.factor() + cursorShape: drag.active ? Qt.DragMoveCursor : (containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor) + } + + Behavior on scale { + NumberAnimation { + duration: 500 + } + + } + + Behavior on rotation { + NumberAnimation { + duration: 500 + } + + } + } diff --git a/src/qml/exam/ResultLabel.qml b/src/qml/exam/ResultLabel.qml index 248f80fa6ce4459c6f301ed1cd7b0fa5ec913d8b..2b91532cecb680cec4324773c9d3f6145100e3da 100644 --- a/src/qml/exam/ResultLabel.qml +++ b/src/qml/exam/ResultLabel.qml @@ -2,46 +2,56 @@ * Copyright (C) 2017-2020 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 +import QtQuick 2.12 Rectangle { - id: label - property alias score: result.text - property color bg: activPal.button - property int index: -1 - property bool hi: false - - signal getTip() - - height: nootkaWindow.width / 45; width: height * 2 - color: resultArea.containsMouse || hi ? activPal.highlight : Qt.tint(activPal.mid, NOO.alpha(bg, 40)) - z: 15 - - Text { - id: result - font.pixelSize: parent.height * 0.75 - anchors.fill: parent - verticalAlignment: Text.AlignVCenter; horizontalAlignment: Text.AlignHCenter - color: resultArea.containsMouse || hi ? activPal.highlightedText : activPal.buttonText - } - - MouseArea { - id: resultArea - anchors.fill: parent - hoverEnabled: !NOO.isAndroid() - onClicked: more() - onContainsMouseChanged: { - if (GLOB.showHints) { - if (containsMouse) - getTip() - else - NOO.setStatusTip("", Item.Top) - } + id: label + + property alias score: result.text + property color bg: activPal.button + property int index: -1 + property bool hi: false + + signal getTip() + + function more() { + resultsItem.more(label); + } + + function showTip(tip) { + NOO.setStatusTip(tip, Item.Top); + } + + height: nootkaWindow.width / 45 + width: height * 2 + color: resultArea.containsMouse || hi ? activPal.highlight : Qt.tint(activPal.mid, NOO.alpha(bg, 40)) + z: 15 + + Text { + id: result + + font.pixelSize: parent.height * 0.75 + anchors.fill: parent + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + color: resultArea.containsMouse || hi ? activPal.highlightedText : activPal.buttonText + } + + MouseArea { + id: resultArea + + anchors.fill: parent + hoverEnabled: !NOO.isAndroid() + onClicked: more() + onContainsMouseChanged: { + if (GLOB.showHints) { + if (containsMouse) + getTip(); + else + NOO.setStatusTip("", Item.Top); + } + } } - } - function more() { resultsItem.more(label) } - function showTip(tip) { NOO.setStatusTip(tip, Item.Top) } } diff --git a/src/qml/exam/ResultTip.qml b/src/qml/exam/ResultTip.qml index 54873ff6fb0d770e78b8dbcd1235aaf8de32b56b..a17d18908a7f72997a75f30d10b7e90168306400 100644 --- a/src/qml/exam/ResultTip.qml +++ b/src/qml/exam/ResultTip.qml @@ -2,53 +2,82 @@ * 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 Qt5Compat.GraphicalEffects - import Nootka 1.0 +import Qt5Compat.GraphicalEffects +import QtQuick 2.12 Item { - id: resultTip - - property real targetY: shortEdge / 80 - property alias color: txt.color - property alias text: txt.text - property real shortEdge: Math.min(executor.height, executor.width) - - anchors { right: parent.right; rightMargin: shortEdge / 12 } - - width: txt.width; height: txt.height - z: 501 // above status tip rectangle - - Text { - id: txt - font { pixelSize: (shortEdge / 15) * (1 - 0.2 * (lineCount - 1)); bold: true } - visible: false - horizontalAlignment: Text.AlignHCenter; textFormat: Text.StyledText - } - - DropShadow { - anchors.fill: txt - horizontalOffset: txt.font.pixelSize / 12 - verticalOffset: horizontalOffset - radius: shortEdge / 100 - samples: radius * 2 + 1 - color: activPal.shadow - source: txt - } - - transformOrigin: Item.Top - - Component.onCompleted: { - if (GLOB.useAnimations) - anim.running = true - y = GLOB.useAnimations ? -2 * height : targetY - } - - SequentialAnimation { - id: anim - NumberAnimation { target: resultTip; property: "y"; to: targetY; duration: 200 } - NumberAnimation { target: resultTip; property: "scale"; to: 2; duration: 200 } - NumberAnimation { target: resultTip; property: "scale"; to: 1; duration: 300 } - } + id: resultTip + + property real targetY: shortEdge / 80 + property alias color: txt.color + property alias text: txt.text + property real shortEdge: Math.min(executor.height, executor.width) + + width: txt.width + height: txt.height + z: 501 // above status tip rectangle + transformOrigin: Item.Top + Component.onCompleted: { + if (GLOB.useAnimations) + anim.running = true; + + y = GLOB.useAnimations ? -2 * height : targetY; + } + + anchors { + right: parent.right + rightMargin: shortEdge / 12 + } + + Text { + id: txt + + visible: false + horizontalAlignment: Text.AlignHCenter + textFormat: Text.StyledText + + font { + pixelSize: (shortEdge / 15) * (1 - 0.2 * (lineCount - 1)) + bold: true + } + + } + + DropShadow { + anchors.fill: txt + horizontalOffset: txt.font.pixelSize / 12 + verticalOffset: horizontalOffset + radius: shortEdge / 100 + samples: radius * 2 + 1 + color: activPal.shadow + source: txt + } + + SequentialAnimation { + id: anim + + NumberAnimation { + target: resultTip + property: "y" + to: targetY + duration: 200 + } + + NumberAnimation { + target: resultTip + property: "scale" + to: 2 + duration: 200 + } + + NumberAnimation { + target: resultTip + property: "scale" + to: 1 + duration: 300 + } + + } + } diff --git a/src/qml/exam/StartExam.qml b/src/qml/exam/StartExam.qml index d884a87227e782f34b707f1a895c6f6df0cb8c31..d7f2859565ebe481887c82f6eab43c9ce6545613 100644 --- a/src/qml/exam/StartExam.qml +++ b/src/qml/exam/StartExam.qml @@ -2,325 +2,457 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" +import "../level" +import Nootka 1.0 +import Nootka.Exam 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 -import Nootka.Exam 1.0 -import "../level" -import "../" +TstartExamItem { + id: startDialog + // level selector visible only for tablet or landscape layout + property bool hideSelector: NOO.isAndroid() ? width / (NOO.fingerPixels() / 0.7) < 15 : height > width + property var exExGotIt: null + property bool remaindMeLater: GLOB.gotIt("examOrExercise", false) -TstartExamItem { - id: startDialog - - width: parent.width; height: parent.height - - // level selector visible only for tablet or landscape layout - property bool hideSelector: NOO.isAndroid() ? width / (NOO.fingerPixels() / 0.7) < 15 : height > width - - Column { - id: startCol - width: parent.width; height: parent.height - - spacing: NOO.isAndroid() ? - Math.min(NOO.factor() * 2, - (startDialog.height - upperRow.height - infoText.height - levelWrapper.height - grid1.height - grid2.height) / 4.5) - : NOO.factor() - topPadding: NOO.factor() / 4 - - Row { - id: upperRow - spacing: NOO.factor() * (NOO.isAndroid() || hideSelector ? 2 : 4) - anchors.horizontalCenter: parent.horizontalCenter - TiconButton { - anchors.verticalCenter: parent.verticalCenter - pixmap: NOO.pix("help"); iconHeight: startDialog.height / 15 - text: NOO.TR("QShortcut", "Help") - onClicked: examOrExerGotIt() - color: enabled ? Qt.tint(activPal.button, NOO.alpha("orange", NOO.isAndroid() ? 40 : 0)) : disdPal.button - } - Grid { - spacing: NOO.factor() * (NOO.isAndroid() || hideSelector ? 0.5 : 1) - anchors.verticalCenter: parent.verticalCenter - horizontalItemAlignment: Grid.AlignHCenter; verticalItemAlignment: Grid.AlignVCenter - columns: hideSelector ? 1 : 2 - Text { text: qsTr("student name:"); color: activPal.text } - TtextField { - id: userNameIn - placeholderText: qsTr("Enter your name or nick-name.") - font.pixelSize: NOO.factor(); maximumLength: 40 - width: NOO.factor() * (NOO.isAndroid() ? 19 : 25) - horizontalAlignment: TextInput.AlignHCenter - text: GLOB.student - } - } - TiconButton { - anchors.verticalCenter: parent.verticalCenter - pixmap: NOO.pix("levelCreator"); iconHeight: startDialog.height / 15 - text: NOO.TR("TlevelCreatorItem", "Level creator").replace(" ", "\n") - color: enabled ? Qt.tint(activPal.button, NOO.alpha("teal", NOO.isAndroid() ? 40 : 0)) : disdPal.button - onClicked: { - dialLoader.close() - nootkaWindow.showDialog(3) // Nootka.LevelCreator + function examOrExerGotIt() { + if (!exExGotIt) + exExGotIt = Qt.createComponent("qrc:/gotit/ExamOrExercise.qml").createObject(startDialog, { + "remaindChecked": remaindMeLater + }); + + exExGotIt.open(); + } + + function start(action, argument) { + if (userNameIn.text === "") { + noNameAnim.running = true; + noNamePopup.open(); + return ; } - } + GLOB.student = userNameIn.text; + GLOB.isExam = true; + nootkaWindow.executor.init(action, argument); + dialLoader.close(); } - Text { - id: infoText - text: qsTr("To start exercising or to pass new exam put in your name and select a level. To continue the previous exam, select it from the list or load from file.") - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width * 0.9; horizontalAlignment: Text.AlignHCenter; color: activPal.text - font { bold: true; pixelSize: NOO.factor() * 0.8 } - wrapMode: Text.WordWrap + width: parent.width + height: parent.height + onContinueExam: start(Texecutor.ContinueExam, examFile) + Component.onCompleted: { + dialLoader.standardButtons = 0; + if (!NOO.isAndroid()) + dialLoader.title = qsTr("Start exercises or an exam"); + } + Component.onDestruction: { + if (exExGotIt) + GLOB.setGotIt("examOrExercise", exExGotIt.remaindChecked); - Item { - id: levelWrapper - anchors.horizontalCenter: parent.horizontalCenter - width: childrenRect.width; height: childrenRect.height - LevelsSelector { - id: selector - parent: hideSelector ? selPopLoader.item.contentItem : levelWrapper - width: startDialog.width - NOO.factor() * (hideSelector ? 2 : 1) - height: hideSelector ? startDialog.height * 0.7 : startDialog.height - upperRow.height - grid1.height - grid2.height - infoText.height - - (NOO.isAndroid() ? 4 : 6) * startCol.spacing - } } - Grid { - id: grid1 - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) - columns: hideSelector ? 1 : 2 - Tframe { - width: startDialog.width / (hideSelector ? 1 : 2) - NOO.factor() + Column { + id: startCol + + width: parent.width + height: parent.height + spacing: NOO.isAndroid() ? Math.min(NOO.factor() * 2, (startDialog.height - upperRow.height - infoText.height - levelWrapper.height - grid1.height - grid2.height) / 4.5) : NOO.factor() + topPadding: NOO.factor() / 4 + Row { - spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) - TiconButton { - enabled: selector.levelId > -1 || prevLevelName() !== "" - iconHeight: startDialog.height / 15 - pixmap: NOO.pix("practice") - text: qsTr("Start exercise on level:") - onClicked: start(Texecutor.StartExercise, selector.levelId > -1 ? selector.currentLevelVar() : prevLevel()) - color: enabled ? Qt.tint(activPal.button, NOO.alpha("green", NOO.isAndroid() ? 40 : 0)) : disdPal.button - } - Text { - anchors.verticalCenter: parent.verticalCenter - text: "<b>" + (selector.levelId > -1 ? selector.levelName(selector.levelId) : (prevLevelName() === "" ? qsTr("No level was selected!") : prevLevelName())) + "</b>" - color: activPal.text; font.pixelSize: NOO.factor() * 0.8 - } + id: upperRow + + spacing: NOO.factor() * (NOO.isAndroid() || hideSelector ? 2 : 4) + anchors.horizontalCenter: parent.horizontalCenter + + TiconButton { + anchors.verticalCenter: parent.verticalCenter + pixmap: NOO.pix("help") + iconHeight: startDialog.height / 15 + text: NOO.TR("QShortcut", "Help") + onClicked: examOrExerGotIt() + color: enabled ? Qt.tint(activPal.button, NOO.alpha("orange", NOO.isAndroid() ? 40 : 0)) : disdPal.button + } + + Grid { + spacing: NOO.factor() * (NOO.isAndroid() || hideSelector ? 0.5 : 1) + anchors.verticalCenter: parent.verticalCenter + horizontalItemAlignment: Grid.AlignHCenter + verticalItemAlignment: Grid.AlignVCenter + columns: hideSelector ? 1 : 2 + + Text { + text: qsTr("student name:") + color: activPal.text + } + + TtextField { + id: userNameIn + + placeholderText: qsTr("Enter your name or nick-name.") + font.pixelSize: NOO.factor() + maximumLength: 40 + width: NOO.factor() * (NOO.isAndroid() ? 19 : 25) + horizontalAlignment: TextInput.AlignHCenter + text: GLOB.student + } + + } + + TiconButton { + anchors.verticalCenter: parent.verticalCenter + pixmap: NOO.pix("levelCreator") + iconHeight: startDialog.height / 15 + text: NOO.TR("TlevelCreatorItem", "Level creator").replace(" ", "\n") + color: enabled ? Qt.tint(activPal.button, NOO.alpha("teal", NOO.isAndroid() ? 40 : 0)) : disdPal.button + onClicked: { + dialLoader.close(); + nootkaWindow.showDialog(3); // Nootka.LevelCreator + } + } + } - } - Tframe { - width: startDialog.width / (hideSelector ? 1 : 2) - NOO.factor() - Row { - spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) - TiconButton { - enabled: selector.levelId !== -1 - iconHeight: startDialog.height / 15 - pixmap: NOO.pix("exam") - text: qsTr("Pass new exam on level:") - onClicked: start(Texecutor.NewExam, selector.currentLevelVar()) - color: enabled ? Qt.tint(activPal.button, NOO.alpha("yellow", NOO.isAndroid() ? 40 : 0)) : disdPal.button - } - Text { - anchors.verticalCenter: parent.verticalCenter - text: "<b>" + (selector.levelId > -1 ? selector.levelName(selector.levelId) : qsTr("No level was selected!")) - color: activPal.text; font.pixelSize: NOO.factor() * 0.8 - } + + Text { + id: infoText + + text: qsTr("To start exercising or to pass new exam put in your name and select a level. To continue the previous exam, select it from the list or load from file.") + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width * 0.9 + horizontalAlignment: Text.AlignHCenter + color: activPal.text + wrapMode: Text.WordWrap + + font { + bold: true + pixelSize: NOO.factor() * 0.8 + } + } - } - } - Grid { - id: grid2 - anchors { horizontalCenter: parent.horizontalCenter } - width: startDialog.width - NOO.factor() - spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) - columns: hideSelector ? 1 : 2 - Tframe { - id: lastExamFrame - width: hideSelector ? startDialog.width - NOO.factor() : parent.width - contFrame.width - exitFrame.width - 2 * NOO.factor() - Row { - spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) - TiconButton { - id: lastExamButt - iconHeight: startDialog.height / 15 - pixmap: NOO.pix("exam") - text: qsTr("Latest exam") - enabled: lastExamFile !== "" - onClicked: start(Texecutor.ContinueExam, lastExamFile) - color: enabled ? Qt.tint(activPal.button, NOO.alpha("orange", NOO.isAndroid() ? 40 : 0)) : disdPal.button - } - Text { - width: lastExamFrame.width - lastExamButt.width - 3 * NOO.factor() - anchors.verticalCenter: parent.verticalCenter - text: lastExamButt.enabled ? lastExamFile : NOO.TR("QPrintSettingsOutput", "None") - color: activPal.text; font { pixelSize: NOO.factor() * 0.8; bold: true } - wrapMode: Text.WordWrap; horizontalAlignment: Text.AlignHCenter - maximumLineCount: 2; elide: Text.ElideRight - } + Item { + id: levelWrapper + + anchors.horizontalCenter: parent.horizontalCenter + width: childrenRect.width + height: childrenRect.height + + LevelsSelector { + id: selector + + parent: hideSelector ? selPopLoader.item.contentItem : levelWrapper + width: startDialog.width - NOO.factor() * (hideSelector ? 2 : 1) + height: hideSelector ? startDialog.height * 0.7 : startDialog.height - upperRow.height - grid1.height - grid2.height - infoText.height - (NOO.isAndroid() ? 4 : 6) * startCol.spacing + } + } - } - Row { - spacing: NOO.factor() - Tframe { - id: contFrame - border.width: 0 - Row { - TiconButton { - iconHeight: startDialog.height / 15 - pixmap: NOO.pix("exam") - text: qsTr("Select an exam to continue") + " ⋮" - onClicked: menu.open() - color: enabled ? Qt.tint(activPal.button, NOO.alpha("orange", NOO.isAndroid() ? 40 : 0)) : disdPal.button + + Grid { + id: grid1 + + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) + columns: hideSelector ? 1 : 2 + + Tframe { + width: startDialog.width / (hideSelector ? 1 : 2) - NOO.factor() + + Row { + spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) + + TiconButton { + enabled: selector.levelId > -1 || prevLevelName() !== "" + iconHeight: startDialog.height / 15 + pixmap: NOO.pix("practice") + text: qsTr("Start exercise on level:") + onClicked: start(Texecutor.StartExercise, selector.levelId > -1 ? selector.currentLevelVar() : prevLevel()) + color: enabled ? Qt.tint(activPal.button, NOO.alpha("green", NOO.isAndroid() ? 40 : 0)) : disdPal.button + } + + Text { + anchors.verticalCenter: parent.verticalCenter + text: "<b>" + (selector.levelId > -1 ? selector.levelName(selector.levelId) : (prevLevelName() === "" ? qsTr("No level was selected!") : prevLevelName())) + "</b>" + color: activPal.text + font.pixelSize: NOO.factor() * 0.8 + } + + } + } - } + + Tframe { + width: startDialog.width / (hideSelector ? 1 : 2) - NOO.factor() + + Row { + spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) + + TiconButton { + enabled: selector.levelId !== -1 + iconHeight: startDialog.height / 15 + pixmap: NOO.pix("exam") + text: qsTr("Pass new exam on level:") + onClicked: start(Texecutor.NewExam, selector.currentLevelVar()) + color: enabled ? Qt.tint(activPal.button, NOO.alpha("yellow", NOO.isAndroid() ? 40 : 0)) : disdPal.button + } + + Text { + anchors.verticalCenter: parent.verticalCenter + text: "<b>" + (selector.levelId > -1 ? selector.levelName(selector.levelId) : qsTr("No level was selected!")) + color: activPal.text + font.pixelSize: NOO.factor() * 0.8 + } + + } + + } + } - Tframe { - id: exitFrame - border.width: 0 - Row { - TiconButton { - iconHeight: startDialog.height / 15 - pixmap: NOO.pix("exit"); text: NOO.TR("QShortcut", "Exit") - onClicked: dialLoader.close() - color: enabled ? Qt.tint(activPal.button, NOO.alpha("red", NOO.isAndroid() ? 60 : 0)) : disdPal.button + + Grid { + id: grid2 + + width: startDialog.width - NOO.factor() + spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) + columns: hideSelector ? 1 : 2 + + anchors { + horizontalCenter: parent.horizontalCenter } - } + + Tframe { + id: lastExamFrame + + width: hideSelector ? startDialog.width - NOO.factor() : parent.width - contFrame.width - exitFrame.width - 2 * NOO.factor() + + Row { + spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) + + TiconButton { + id: lastExamButt + + iconHeight: startDialog.height / 15 + pixmap: NOO.pix("exam") + text: qsTr("Latest exam") + enabled: lastExamFile !== "" + onClicked: start(Texecutor.ContinueExam, lastExamFile) + color: enabled ? Qt.tint(activPal.button, NOO.alpha("orange", NOO.isAndroid() ? 40 : 0)) : disdPal.button + } + + Text { + width: lastExamFrame.width - lastExamButt.width - 3 * NOO.factor() + anchors.verticalCenter: parent.verticalCenter + text: lastExamButt.enabled ? lastExamFile : NOO.TR("QPrintSettingsOutput", "None") + color: activPal.text + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + maximumLineCount: 2 + elide: Text.ElideRight + + font { + pixelSize: NOO.factor() * 0.8 + bold: true + } + + } + + } + + } + + Row { + spacing: NOO.factor() + + Tframe { + id: contFrame + + border.width: 0 + + Row { + TiconButton { + iconHeight: startDialog.height / 15 + pixmap: NOO.pix("exam") + text: qsTr("Select an exam to continue") + " ⋮" + onClicked: menu.open() + color: enabled ? Qt.tint(activPal.button, NOO.alpha("orange", NOO.isAndroid() ? 40 : 0)) : disdPal.button + } + + } + + } + + Tframe { + id: exitFrame + + border.width: 0 + + Row { + TiconButton { + iconHeight: startDialog.height / 15 + pixmap: NOO.pix("exit") + text: NOO.TR("QShortcut", "Exit") + onClicked: dialLoader.close() + color: enabled ? Qt.tint(activPal.button, NOO.alpha("red", NOO.isAndroid() ? 60 : 0)) : disdPal.button + } + + } + + } + + } + } - } + } - } - - Tmenu { - id: menu - width: Math.min(NOO.factor() * 25, startDialog.width * 0.8) - height: Math.min(startDialog.height * 0.8, contentItem.contentHeight) - y: (startDialog.height - height) / 2; x: (startDialog.width - width) / 2 - modal: true - contentItem: ListView { - clip: true - ScrollBar.vertical: ScrollBar { active: true } - model: recentModel - delegate: MenuButton { - width: menu.width - action: modelData - onClicked: menu.close() - Rectangle { width: parent.width; height: index === recentModel.length - 1 ? 0 : 1; color: activPal.text; y: parent.height - 1 } - } + + Tmenu { + id: menu + + width: Math.min(NOO.factor() * 25, startDialog.width * 0.8) + height: Math.min(startDialog.height * 0.8, contentItem.contentHeight) + y: (startDialog.height - height) / 2 + x: (startDialog.width - width) / 2 + modal: true + + contentItem: ListView { + clip: true + model: recentModel + + ScrollBar.vertical: ScrollBar { + active: true + } + + delegate: MenuButton { + width: menu.width + action: modelData + onClicked: menu.close() + + Rectangle { + width: parent.width + height: index === recentModel.length - 1 ? 0 : 1 + color: activPal.text + y: parent.height - 1 + } + + } + + } + } - } - TpopupDialog { - id: noNamePopup - bgColor: Qt.tint(activPal.window, NOO.alpha("red", 20)) - border { color: "red"; width: NOO.factor() / 4.0 } + TpopupDialog { + id: noNamePopup - rejectButton.text: NOO.TR("QShortcut", "OK") - rejectButton.pixmap: NOO.pix("check") - acceptButton.visible: false + bgColor: Qt.tint(activPal.window, NOO.alpha("red", 20)) + rejectButton.text: NOO.TR("QShortcut", "OK") + rejectButton.pixmap: NOO.pix("check") + acceptButton.visible: false + width: noNameTxt.width + NOO.factor() * 2 + height: noNameTxt.height + NOO.factor() * 5 + onRejected: { + noNameAnim.running = false; + userNameIn.bg.color = activPal.base; + } - width: noNameTxt.width + NOO.factor() * 2; height: noNameTxt.height + NOO.factor() * 5 + border { + color: "red" + width: NOO.factor() / 4 + } + + Text { + id: noNameTxt + + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + font.pixelSize: NOO.factor() * 1.5 + text: qsTr("Give an user name!") + } - Text { - id: noNameTxt - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text - font.pixelSize: NOO.factor() * 1.5 - text: qsTr("Give an user name!") } - onRejected: { - noNameAnim.running = false - userNameIn.bg.color = activPal.base + Loader { + id: selPopLoader + + active: hideSelector + + sourceComponent: TpopupDialog { + padding: 0 + rejectButton.visible: false + parent: startDialog + width: selector.width + NOO.factor() + height: selector.height + NOO.factor() * 4 + } + } - } - - Loader { - id: selPopLoader - active: hideSelector - sourceComponent: TpopupDialog { - padding: 0 - rejectButton.visible: false - parent: startDialog - width: selector.width + NOO.factor(); height: selector.height + NOO.factor() * 4 + + Loader { + active: hideSelector + + sourceComponent: Tframe { + parent: levelWrapper + + Row { + spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) + + TiconButton { + iconHeight: startDialog.height / 15 + pixmap: NOO.pix("nootka-level") + text: NOO.TR("LevelsPage", "Level name:") + onClicked: selPopLoader.item.open() + color: enabled ? Qt.tint(activPal.button, NOO.alpha(activPal.highlight, NOO.isAndroid() ? 40 : 0)) : disdPal.button + } + + Text { + anchors.verticalCenter: parent.verticalCenter + text: "<b>" + (selector.levelId > -1 ? selector.levelName(selector.levelId) : qsTr("No level was selected!")) + color: activPal.text + font.pixelSize: NOO.factor() * 0.8 + } + + } + + } + } - } - - Loader { - active: hideSelector - sourceComponent: Tframe { - parent: levelWrapper - Row { - spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) - TiconButton { - iconHeight: startDialog.height / 15 - pixmap: NOO.pix("nootka-level") - text: NOO.TR("LevelsPage", "Level name:") - onClicked: selPopLoader.item.open() - color: enabled ? Qt.tint(activPal.button, NOO.alpha(activPal.highlight, NOO.isAndroid() ? 40 : 0)) : disdPal.button + + SequentialAnimation { + id: noNameAnim + + loops: Animation.Infinite + + ColorAnimation { + target: userNameIn.bg + property: "color" + to: "red" + duration: 500 } - Text { - anchors.verticalCenter: parent.verticalCenter - text: "<b>" + (selector.levelId > -1 ? selector.levelName(selector.levelId) : qsTr("No level was selected!")) - color: activPal.text; font.pixelSize: NOO.factor() * 0.8 + + PauseAnimation { + duration: 300 } - } - } - } - - SequentialAnimation { - id: noNameAnim - loops: Animation.Infinite - ColorAnimation { target: userNameIn.bg; property: "color"; to: "red"; duration: 500 } - PauseAnimation { duration: 300 } - ColorAnimation { target: userNameIn.bg; property: "color"; to: activPal.base; duration: 500 } - PauseAnimation { duration: 300 } - } - - onContinueExam: start(Texecutor.ContinueExam, examFile) - - Component.onCompleted: { - dialLoader.standardButtons = 0 - if (!NOO.isAndroid()) - dialLoader.title = qsTr("Start exercises or an exam") - } - - Component.onDestruction: { - if (exExGotIt) - GLOB.setGotIt("examOrExercise", exExGotIt.remaindChecked) - } - - property var exExGotIt: null - property bool remaindMeLater: GLOB.gotIt("examOrExercise", false) - - Timer { - interval: 500 - running: true - onTriggered: { - if (remaindMeLater) - examOrExerGotIt() + + ColorAnimation { + target: userNameIn.bg + property: "color" + to: activPal.base + duration: 500 + } + + PauseAnimation { + duration: 300 + } + } - } - - function examOrExerGotIt() { - if (!exExGotIt) - exExGotIt = Qt.createComponent("qrc:/gotit/ExamOrExercise.qml").createObject(startDialog, { "remaindChecked": remaindMeLater } ) - exExGotIt.open() - } - - function start(action, argument) { - if (userNameIn.text === "") { - noNameAnim.running = true - noNamePopup.open() - return + + Timer { + interval: 500 + running: true + onTriggered: { + if (remaindMeLater) + examOrExerGotIt(); + + } } - GLOB.student = userNameIn.text - GLOB.isExam = true - nootkaWindow.executor.init(action, argument) - dialLoader.close() - } + } diff --git a/src/qml/exam/TsuggestExam.qml b/src/qml/exam/TsuggestExam.qml index b168c4ab3447ab879dede7f16266efc0ab899321..e4309bfe435ca1a7a41c20d5e6ef95c72780b92b 100644 --- a/src/qml/exam/TsuggestExam.qml +++ b/src/qml/exam/TsuggestExam.qml @@ -2,63 +2,94 @@ * Copyright (C) 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 Nootka 1.0 -import "../" +TpopupDialog { + property alias entireVisible: entireRadio.visible + caption: qsTr("Start an exam") + bgColor: Qt.tint(activPal.window, NOO.alpha(GLOB.correctColor, 20)) + visible: true + modal: true + width: outerCol.width * 1.2 + height: outerCol.height + NOO.factor() * 7 + glowRect.radius: NOO.factor() + acceptButton.text: NOO.TR("QMessageBox", "OK") + rejectButton.visible: false + onAccepted: { + for (var b = 0; b < gr.buttons.length; ++b) { + if (gr.buttons[b].checked) { + executor.suggestDialogClosed(b); + break; + } + } + } + onRejected: executor.suggestDialogClosed(-1) + onClosed: destroy() -TpopupDialog { - property alias entireVisible: entireRadio.visible + border { + color: GLOB.correctColor + width: NOO.factor() / 4 + } - caption: qsTr("Start an exam") + ButtonGroup { + id: gr - bgColor: Qt.tint(activPal.window, NOO.alpha(GLOB.correctColor, 20)) - border { color: GLOB.correctColor; width: NOO.factor() / 4.0 } - visible: true; modal: true - width: outerCol.width * 1.2; height: outerCol.height + NOO.factor() * 7 - glowRect.radius: NOO.factor() + buttons: innerCol.children + } - acceptButton.text: NOO.TR("QMessageBox", "OK") - rejectButton.visible: false + Column { + id: outerCol - ButtonGroup { id: gr; buttons: innerCol.children } + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter - Column { - id: outerCol - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter + Text { + color: activPal.text + text: qsTr("You are very good in this exercise!<br>Would you like to pass an exam on the same level and got a certificate?") + horizontalAlignment: Text.AlignHCenter - Text { - color: activPal.text - font { pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.2); bold: true } - text: qsTr("You are very good in this exercise!<br>Would you like to pass an exam on the same level and got a certificate?") - horizontalAlignment: Text.AlignHCenter - } + font { + pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.2) + bold: true + } - Column { - id: innerCol - spacing: NOO.factor() / 2 - anchors.horizontalCenter: parent.horizontalCenter - TradioButton { text: qsTr("Sure! Lets start an exam!"); checked: true } - TradioButton { text: qsTr("Not now, ask me for a moment.") } - TradioButton { id: entireRadio; text: qsTr("No thanks, but check entire melody from now.") } - TradioButton { text: qsTr("Not in this exercise.") } - TradioButton { text: qsTr("Never more suggest me to start an exam!") } - } - } - - onAccepted: { - for (var b = 0; b < gr.buttons.length; ++b) { - if (gr.buttons[b].checked) { - executor.suggestDialogClosed(b) - break - } - } - } + } + + Column { + id: innerCol + + spacing: NOO.factor() / 2 + anchors.horizontalCenter: parent.horizontalCenter + + TradioButton { + text: qsTr("Sure! Lets start an exam!") + checked: true + } + + TradioButton { + text: qsTr("Not now, ask me for a moment.") + } - onRejected: executor.suggestDialogClosed(-1) + TradioButton { + id: entireRadio + + text: qsTr("No thanks, but check entire melody from now.") + } + + TradioButton { + text: qsTr("Not in this exercise.") + } + + TradioButton { + text: qsTr("Never more suggest me to start an exam!") + } + + } + + } - onClosed: destroy() } diff --git a/src/qml/gotit/ExamFlow.qml b/src/qml/gotit/ExamFlow.qml index 9ee04a01550abc4cb4e4407300bc5eb6c422abf5..10e323828bec53a423846a14dc8c2bf9ebd6e521 100644 --- a/src/qml/gotit/ExamFlow.qml +++ b/src/qml/gotit/ExamFlow.qml @@ -2,165 +2,261 @@ * 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 Nootka 1.0 import "../" import "../exam" +import Nootka 1.0 import Nootka.Main 1.0 - +import QtQuick 2.12 GotIt { - gotItType: TgotIt.GotExamFlow - onClicked: close() - - // private - property real bigImg: NOO.factor() * (NOO.isAndroid() ? 1.8 : 3) - property var leftTexts: [ qsTranslate("TexamHelp", "Exercises"), qsTranslate("TexamHelp", "Exams"), qsTranslate("TexamHelp", "Settings") ] - property var leftImages: [ "practice", "exam", "exam-settings" ] - property alias executor: helpCol - - Component { - id: tipComp - GlowRect { - property alias text: glowText.text - width: glowText.width; height: glowText.height; radius: NOO.factor() - color: Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 50)) - border { width: NOO.factor() / 6; color: activPal.highlight } - Text { - id: glowText - color: activPal.text; padding: NOO.factor() - } + // private + property real bigImg: NOO.factor() * (NOO.isAndroid() ? 1.8 : 3) + property var leftTexts: [qsTranslate("TexamHelp", "Exercises"), qsTranslate("TexamHelp", "Exams"), qsTranslate("TexamHelp", "Settings")] + property var leftImages: ["practice", "exam", "exam-settings"] + property alias executor: helpCol + + gotItType: TgotIt.GotExamFlow + onClicked: close() + + Component { + id: tipComp + + GlowRect { + property alias text: glowText.text + + width: glowText.width + height: glowText.height + radius: NOO.factor() + color: Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 50)) + + border { + width: NOO.factor() / 6 + color: activPal.highlight + } + + Text { + id: glowText + + color: activPal.text + padding: NOO.factor() + } + + } + } - } - - Component { - id: textComp - Text { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter - height: NOO.factor() * 7 - leftPadding: NOO.factor() - width: helpCol.width - NOO.factor() - color: activPal.text; wrapMode: Text.WordWrap + + Component { + id: textComp + + Text { + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + height: NOO.factor() * 7 + leftPadding: NOO.factor() + width: helpCol.width - NOO.factor() + color: activPal.text + wrapMode: Text.WordWrap + } + } - } - - Tflickable { - anchors.fill: parent - contentHeight: helpCol.height + NOO.factor() * 10 - Column { - id: helpCol - width: parent.width - spacing: NOO.factor() - - Item { width: 1; height: NOO.factor() } - Image { - anchors.horizontalCenter: parent.horizontalCenter - source: NOO.pix("help"); height: bigImg; width: height * (sourceSize.width / sourceSize.height) - } - Text { - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text - text: "<h1>" + qsTranslate("TexamHelp", "How does an exercise or an exam work?") + "</h1>" - } - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: bigImg * 2 - Image { source: NOO.pix("practice"); height: bigImg; width: height * (sourceSize.width / sourceSize.height) } - Image { source: NOO.pix("exam"); height: bigImg; width: height * (sourceSize.width / sourceSize.height) } - } - Loader { - sourceComponent: textComp - anchors.horizontalCenter: parent.horizontalCenter - onLoaded: item.text = "<h3>" + qsTranslate("TexamHelp", " Briefly: Nootka give you a question and you give an answer...") + "</h3>" - } - Loader { - sourceComponent: tipComp - anchors.horizontalCenter: parent.horizontalCenter - onLoaded: item.text = gotIt.getQuestionText() - } - Text { - anchors.horizontalCenter: parent.horizontalCenter - leftPadding: NOO.factor(); lineHeight: 1.5 - width: parent.width - NOO.factor(); horizontalAlignment: Text.AlignHCenter - color: activPal.text; wrapMode: Text.WordWrap; textFormat: Text.RichText - text: ("<br><span style=\"background-color: %1\">").arg(NOO.alpha(GLOB.wrongColor, 40)) - + qsTranslate("TexamHelp", "Questions are marked with this color and \"?\" mark.") + "</span><br>" - + qsTranslate("TexamHelp", "To give an answer, select it on <span style=\"%1\">Nootka's element with that color.</span><br>") - .arg("background-color:" + NOO.alpha(GLOB.correctColor, 40)) - } - Image { - anchors.horizontalCenter: parent.horizontalCenter - source: NOO.pix("scr") - width: Math.min(NOO.factor() * 60, parent.width * 0.8); height: width * (sourceSize.height / sourceSize.width) - } - Loader { - sourceComponent: tipComp - anchors.horizontalCenter: parent.horizontalCenter - onLoaded: item.text = gotIt.confirmText() - } - Item { width: 1; height: NOO.factor() * 2 } - Repeater { - model: [ gotIt.practiceExplained(), gotIt.examExplained(), gotIt.optionsText() ] + + Tflickable { + anchors.fill: parent + contentHeight: helpCol.height + NOO.factor() * 10 + Column { - spacing: NOO.factor() - Rectangle { width: helpCol.width; height: 1; color: activPal.text } - Row { - width: helpCol.width * 0.9 - anchors.horizontalCenter: parent.horizontalCenter - spacing: bigImg * (NOO.isAndroid() ? 1 : 2) - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: NOO.factor() - Image { + id: helpCol + + width: parent.width + spacing: NOO.factor() + + Item { + width: 1 + height: NOO.factor() + } + + Image { anchors.horizontalCenter: parent.horizontalCenter - source: NOO.pix(leftImages[index]); height: bigImg * 2 + source: NOO.pix("help") + height: bigImg width: height * (sourceSize.width / sourceSize.height) - } - Text { + } + + Text { anchors.horizontalCenter: parent.horizontalCenter color: activPal.text - text: qsTranslate("TexamHelp", leftTexts[index]) - } - } - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: NOO.factor() - GlowRect { - visible: index !== 2 - width: glowText2.width; height: glowText2.height; radius: NOO.factor() - color: Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 50)) - border { width: NOO.factor() / 6; color: activPal.highlight } - Text { - id: glowText2 - width: NOO.factor() * 30; wrapMode: Text.WordWrap - color: activPal.text; padding: NOO.factor() - text: index === 0 ? gotIt.practiceText() : gotIt.examText() + text: "<h1>" + qsTranslate("TexamHelp", "How does an exercise or an exam work?") + "</h1>" + } + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: bigImg * 2 + + Image { + source: NOO.pix("practice") + height: bigImg + width: height * (sourceSize.width / sourceSize.height) + } + + Image { + source: NOO.pix("exam") + height: bigImg + width: height * (sourceSize.width / sourceSize.height) } - } - Text { + + } + + Loader { + sourceComponent: textComp anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text; wrapMode: Text.WordWrap - width: helpCol.width * 0.9 - bigImg * 4 - text: modelData - } + onLoaded: item.text = "<h3>" + qsTranslate("TexamHelp", " Briefly: Nootka give you a question and you give an answer...") + "</h3>" } - } + + Loader { + sourceComponent: tipComp + anchors.horizontalCenter: parent.horizontalCenter + onLoaded: item.text = gotIt.getQuestionText() + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + leftPadding: NOO.factor() + lineHeight: 1.5 + width: parent.width - NOO.factor() + horizontalAlignment: Text.AlignHCenter + color: activPal.text + wrapMode: Text.WordWrap + textFormat: Text.RichText + text: ("<br><span style=\"background-color: %1\">").arg(NOO.alpha(GLOB.wrongColor, 40)) + qsTranslate("TexamHelp", "Questions are marked with this color and \"?\" mark.") + "</span><br>" + qsTranslate("TexamHelp", "To give an answer, select it on <span style=\"%1\">Nootka's element with that color.</span><br>").arg("background-color:" + NOO.alpha(GLOB.correctColor, 40)) + } + + Image { + anchors.horizontalCenter: parent.horizontalCenter + source: NOO.pix("scr") + width: Math.min(NOO.factor() * 60, parent.width * 0.8) + height: width * (sourceSize.height / sourceSize.width) + } + + Loader { + sourceComponent: tipComp + anchors.horizontalCenter: parent.horizontalCenter + onLoaded: item.text = gotIt.confirmText() + } + + Item { + width: 1 + height: NOO.factor() * 2 + } + + Repeater { + model: [gotIt.practiceExplained(), gotIt.examExplained(), gotIt.optionsText()] + + Column { + spacing: NOO.factor() + + Rectangle { + width: helpCol.width + height: 1 + color: activPal.text + } + + Row { + width: helpCol.width * 0.9 + anchors.horizontalCenter: parent.horizontalCenter + spacing: bigImg * (NOO.isAndroid() ? 1 : 2) + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: NOO.factor() + + Image { + anchors.horizontalCenter: parent.horizontalCenter + source: NOO.pix(leftImages[index]) + height: bigImg * 2 + width: height * (sourceSize.width / sourceSize.height) + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + text: qsTranslate("TexamHelp", leftTexts[index]) + } + + } + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: NOO.factor() + + GlowRect { + visible: index !== 2 + width: glowText2.width + height: glowText2.height + radius: NOO.factor() + color: Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 50)) + + border { + width: NOO.factor() / 6 + color: activPal.highlight + } + + Text { + id: glowText2 + + width: NOO.factor() * 30 + wrapMode: Text.WordWrap + color: activPal.text + padding: NOO.factor() + text: index === 0 ? gotIt.practiceText() : gotIt.examText() + } + + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + wrapMode: Text.WordWrap + width: helpCol.width * 0.9 - bigImg * 4 + text: modelData + } + + } + + } + + } + + } + + Rectangle { + width: helpCol.width + height: 1 + color: activPal.text + } + + LinkText { + horizontalAlignment: Text.AlignHCenter + width: parent.width - NOO.factor() + textFormat: Text.RichText + wrapMode: Text.WordWrap + text: gotIt.getOnlineDoc("exercise-exam") + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + text: qsTranslate("TexamHelp", "GOOD LUCK!") + + font { + pixelSize: NOO.factor() * 2 + bold: true + } + + } + } - } - Rectangle { width: helpCol.width; height: 1; color: activPal.text } - LinkText { - horizontalAlignment: Text.AlignHCenter - width: parent.width - NOO.factor() - textFormat: Text.RichText; wrapMode: Text.WordWrap - text: gotIt.getOnlineDoc("exercise-exam") - } - Text { - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text; font { pixelSize: NOO.factor() * 2; bold: true } - text: qsTranslate("TexamHelp", "GOOD LUCK!") - } + } - } + } diff --git a/src/qml/gotit/ExamOrExercise.qml b/src/qml/gotit/ExamOrExercise.qml index 968b04dd713fe373ccdb8d96838483e4507dc3dd..d037f429adba394abe843f8d6e2ee11d5e70ae66 100644 --- a/src/qml/gotit/ExamOrExercise.qml +++ b/src/qml/gotit/ExamOrExercise.qml @@ -2,50 +2,66 @@ * 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 Nootka 1.0 import "../" +import Nootka 1.0 +import QtQuick 2.12 GotIt { - onClicked: close() - - Tflickable { - anchors.fill: parent - contentHeight: helpCol.height + NOO.factor() * 10 - Column { - id: helpCol - width: parent.width - spacing: NOO.factor() - - Row { - spacing: NOO.factor() * 2 - anchors.horizontalCenter: parent.horizontalCenter - Image { - source: NOO.pix("practice") - height: NOO.factor() * 4; width: height * (sourceSize.width / sourceSize.height) - } - Text { - anchors.verticalCenter: parent.verticalCenter - color: activPal.text - text: qsTranslate("TstartExamDlg", "To exercise or to pass an exam?") - font { bold: true; pixelSize: NOO.factor() * 1.5 } - } - Image { - source: NOO.pix("exam") - height: NOO.factor() * 4; width: height * (sourceSize.width / sourceSize.height) + onClicked: close() + + Tflickable { + anchors.fill: parent + contentHeight: helpCol.height + NOO.factor() * 10 + + Column { + id: helpCol + + width: parent.width + spacing: NOO.factor() + + Row { + spacing: NOO.factor() * 2 + anchors.horizontalCenter: parent.horizontalCenter + + Image { + source: NOO.pix("practice") + height: NOO.factor() * 4 + width: height * (sourceSize.width / sourceSize.height) + } + + Text { + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + text: qsTranslate("TstartExamDlg", "To exercise or to pass an exam?") + + font { + bold: true + pixelSize: NOO.factor() * 1.5 + } + + } + + Image { + source: NOO.pix("exam") + height: NOO.factor() * 4 + width: height * (sourceSize.width / sourceSize.height) + } + + } + + LinkText { + id: exerOrExamText + + anchors.horizontalCenter: parent.horizontalCenter + leftPadding: NOO.factor() + width: parent.width - NOO.factor() + textFormat: Text.RichText + wrapMode: Text.WordWrap + text: gotIt.exerOrExamHelpTxt() + } + } - } - - LinkText { - id: exerOrExamText - anchors.horizontalCenter: parent.horizontalCenter - leftPadding: NOO.factor() - width: parent.width - NOO.factor() - textFormat: Text.RichText - wrapMode: Text.WordWrap - text: gotIt.exerOrExamHelpTxt() - } + } - } + } diff --git a/src/qml/gotit/GotIt.qml b/src/qml/gotit/GotIt.qml index d8bc533c5b880aa928fb4c6077d59d6ada81195a..8cb42014147510c3a170a332961a869b939ed522 100644 --- a/src/qml/gotit/GotIt.qml +++ b/src/qml/gotit/GotIt.qml @@ -2,115 +2,187 @@ * 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 QtQuick.Controls 2.12 -import Qt5Compat.GraphicalEffects - +import "../" import Nootka 1.0 import Nootka.Main 1.0 -import "../" - +import Qt5Compat.GraphicalEffects +import QtQuick 2.12 +import QtQuick.Controls 2.12 Popup { - id: pop + id: pop - signal clicked() + property alias gotItType: gotIt.gotItType + property alias remaindChecked: remaindChB.checked + property alias remindVisible: remaindChB.visible + property alias gotIt: gotIt + property bool showGotIt: true - property alias gotItType: gotIt.gotItType - property alias remaindChecked: remaindChB.checked - property alias remindVisible: remaindChB.visible - property alias gotIt: gotIt - property bool showGotIt: true + signal clicked() - /** + /** * Functions called by @p HelpPage to perform particular task on help pages, if any. */ - function stop() {} - function start() {} - - scale: GLOB.useAnimations ? 0 : 1.0 - enter: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 1.0 }} - exit: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 0 }} - - width: parent.width; height: parent.height - padding: 0 - - background: Rectangle { color: activPal.base } - - TgotIt { id: gotIt } - - RectangularGlow { - z: 10 - visible: showGotIt - anchors.fill: bg - glowRadius: NOO.factor() / 2 - color: activPal.text - cornerRadius: bg.radius + glowRadius - transformOrigin: Item.BottomRight - scale: GLOB.useAnimations && ma.pressed ? 0.95 : 1.0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - } - - Rectangle { - id: bg - visible: showGotIt - z: 10 - width: gotColl.width + 2 * radius + NOO.factor() - height: gotColl.height + 1.5 * radius - radius: (gotColl.height + 4 * NOO.factor()) / 4 - x: parent.width - width + radius + NOO.factor(); y: parent.height - height + radius + NOO.factor() - color: ma.containsMouse ? activPal.highlight : Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 150)) - transformOrigin: Item.BottomRight - scale: GLOB.useAnimations && ma.pressed ? 0.95 : 1.0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - MouseArea { - id: ma - anchors.fill: parent - hoverEnabled: !NOO.isAndroid() - onClicked: pop.clicked() + function stop() { } - } - - Column { - id: gotColl - visible: showGotIt - z: 10 - x: parent.width - width - NOO.factor() / 2; y: parent.height - height - transformOrigin: Item.BottomRight - scale: GLOB.useAnimations && ma.pressed ? 0.95 : 1.0 - Text { - id: gotText - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text - font { pixelSize: NOO.factor() * 2; bold: true } - style: ma.containsMouse ? Text.Sunken : Text.Normal - styleColor: activPal.base; transformOrigin: Item.Top - text: qsTr("GOT IT!") - Behavior on scale { NumberAnimation { duration: 150 }} - Timer { - running: showGotIt - interval: 2000; repeat: true - onTriggered: { - if (interval > 300) { - interval = 200 - gotText.scale = 1.3 - } else { - interval = 2000 - gotText.scale = 1 - } - } - } + + function start() { } - Row { - TcheckBox { id: remaindChB } - Text { - anchors.verticalCenter: parent.verticalCenter + + scale: GLOB.useAnimations ? 0 : 1 + width: parent.width + height: parent.height + padding: 0 + + TgotIt { + id: gotIt + } + + RectangularGlow { + z: 10 + visible: showGotIt + anchors.fill: bg + glowRadius: NOO.factor() / 2 color: activPal.text - text: qsTr("remind me next time") - } + cornerRadius: bg.radius + glowRadius + transformOrigin: Item.BottomRight + scale: GLOB.useAnimations && ma.pressed ? 0.95 : 1 + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + } - Item { width: NOO.factor(); height: NOO.factor() / 2 } - } -} + Rectangle { + id: bg + + visible: showGotIt + z: 10 + width: gotColl.width + 2 * radius + NOO.factor() + height: gotColl.height + 1.5 * radius + radius: (gotColl.height + 4 * NOO.factor()) / 4 + x: parent.width - width + radius + NOO.factor() + y: parent.height - height + radius + NOO.factor() + color: ma.containsMouse ? activPal.highlight : Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 150)) + transformOrigin: Item.BottomRight + scale: GLOB.useAnimations && ma.pressed ? 0.95 : 1 + + MouseArea { + id: ma + + anchors.fill: parent + hoverEnabled: !NOO.isAndroid() + onClicked: pop.clicked() + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + } + + Column { + id: gotColl + + visible: showGotIt + z: 10 + x: parent.width - width - NOO.factor() / 2 + y: parent.height - height + transformOrigin: Item.BottomRight + scale: GLOB.useAnimations && ma.pressed ? 0.95 : 1 + + Text { + id: gotText + + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + style: ma.containsMouse ? Text.Sunken : Text.Normal + styleColor: activPal.base + transformOrigin: Item.Top + text: qsTr("GOT IT!") + + font { + pixelSize: NOO.factor() * 2 + bold: true + } + + Timer { + running: showGotIt + interval: 2000 + repeat: true + onTriggered: { + if (interval > 300) { + interval = 200; + gotText.scale = 1.3; + } else { + interval = 2000; + gotText.scale = 1; + } + } + } + + Behavior on scale { + NumberAnimation { + duration: 150 + } + + } + + } + + Row { + TcheckBox { + id: remaindChB + } + + Text { + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + text: qsTr("remind me next time") + } + + } + + Item { + width: NOO.factor() + height: NOO.factor() / 2 + } + + } + + enter: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 1 + } + + } + + exit: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 0 + } + + } + + background: Rectangle { + color: activPal.base + } + +} diff --git a/src/qml/gotit/HandleScore.qml b/src/qml/gotit/HandleScore.qml index 98ec345aed5fbc6f5793c1a87766fafe6540ef8a..93dbc7fa965ce96f1a35fc72186a542f619f7d02 100644 --- a/src/qml/gotit/HandleScore.qml +++ b/src/qml/gotit/HandleScore.qml @@ -2,260 +2,605 @@ * 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 1.0 import Nootka.Main 1.0 -import "../score" -import "../" +import QtQuick 2.12 GotIt { - id: scoreHow - - gotItType: TgotIt.GotHandleScore - visible: true - - onClicked: close() - - function stop() { - gotAnim.running = false - } - - function start() { - finger.opacity = 0 - finger.scale = 1 - finger.x = parent.width - finger.width - finger.y = parent.height - finger.height - gotScore.noteAdd.active = false - gotScore.scoreToobox.active = false - gotScore.clearScore() - gotScore.noteAdd.yPos = 0 - gotIt.setCursorAlter(0) - gotIt.setWorkRtmValue(3) - descView.currentIndex = -1 - gotAnim.running = true - } - - Image { - id: finger - z: 1050 // above everything and score toolbox - x: parent.width - width; y: parent.height - height - source: NOO.pix("fingerpoint") - width: parent.width * 0.05; height: width - opacity: 0 - } - - Rectangle { // under score - width: gotScore.width * 1.41; height: width; radius: width / 2 - x: width * -0.25; y: height * -0.25 - color: NOO.alpha(activPal.highlight, 50) - } - - MouseArea { // cover score mouse/touch actions - anchors.fill: gotScore - z: 1049 - hoverEnabled: true - } - - Score { - id: gotScore - height: parent.width * 0.35; width: height * 1.1 - bgColor: "transparent" - enableKeySign: true - enableDoubleAccids: true - scoreObj.enableDoubleAccidentals: true - firstStaff.scale: height / firstStaff.linesCount - readOnly: false; scoreObj.editMode: true; scoreObj.allowAdding: visible // HACK - Component.onCompleted: gotIt.score = scoreObj - } - - Rectangle { - width: parent.width * 0.59; height: parent.height - NOO.factor() * 4 - x: parent.width * 0.41 + NOO.factor(); y: NOO.factor() - Column { - anchors.horizontalCenter: parent.hozrizontalCenter - width: parent.width - NOO.factor() * 2 - spacing: NOO.factor() - Text { - anchors.horizontalCenter: parent.hozrizontalCenter - color: activPal.text - font { bold: true; pixelSize: scoreHow.width * 0.03 } - text: qsTr("Editing score with touch") - } - ListView { - id: descView - currentIndex: -1 - clip: true - model: [ - qsTr("Touch and hold area of a note you want to edit."), - qsTr("Move finger left or right to see edited note."), - qsTr("Then move finger up or down to find desired note pitch."), - qsTr("Rise the finger."), - qsTr("If necessary, select accidental or rhythmic value."), - qsTr("Finally, tap selected note shortly.") - ] - width: parent.width - NOO.factor() * 2; height: parent.parent.height - scoreHow.width * 0.04 - NOO.factor() - spacing: NOO.factor() / 2 - delegate: Text { - width: parent.width - NOO.factor() / 2 - text: index + 1 + ". " + modelData - color: activPal.text; wrapMode: Text.WordWrap - font { bold: index === descView.currentIndex; pixelSize: Math.max(scoreHow.width * 0.015, NOO.factor()) } - style: index === descView.currentIndex ? Text.Sunken : Text.Normal - styleColor: activPal.highlight - } - } - } - } - - Timer { // run animation with delay to allow initialize all properties - running: true - interval: 250 - onTriggered: gotAnim.running = true - } + id: scoreHow - /** + /** * NOTICE: QML animation is tricky... * All x, y animated properties are saved before animation starts * and are fixed during all cycle. * So they has to be known and set properly. * This is why we are 'imitating' score toolbox @p factor - it is not known yet when anim starts. */ - property real factor: gotScore.scoreToobox ? gotScore.scoreToobox.factor * 0.9 : NOO.isAndroid() ? NOO.shortScreenSide() * 0.036 : NOO.factor() * 1.08 - property real editPosX: gotScore.x + 23 * gotScore.scale - property real editPosY: gotScore.y + (gotScore.upperLine + 8) * gotScore.scale // upperLine + 4 - property real boxPosX: gotScore.x + 2 + factor * 2.5 + finger.width * 0.2 // in the middle of sharp control on score toolbox - property real boxPosY: (NOO.isAndroid() ? (height - factor * 27) / 2 : NOO.factor() / 2) + factor * 7.5 + finger.width * 0.2 - - SequentialAnimation { - id: gotAnim - PauseAnimation { duration: 500 } - ParallelAnimation { - NumberAnimation { target: finger; property: "opacity"; to: 1 } - NumberAnimation { target: finger; property: "scale"; to: 3; easing.type: Easing.OutBack; duration: 1000 } - NumberAnimation { target: finger; property: "x"; to: editPosX; duration: 1000 } - NumberAnimation { target: finger; property: "y"; to: editPosY; easing.type: Easing.OutBack; duration: 1000 } - } - ScriptAction { - script: { - descView.currentIndex = 0 // touch and hold - gotScore.noteAdd.visible = true - gotScore.scoreToobox.active = false - gotScore.noteAdd.active = true - gotScore.noteAdd.yPos = gotScore.upperLine + 4 - } - } - PauseAnimation { duration: 1000 } - ScriptAction { script: descView.currentIndex = 1 } // Move left or right - ParallelAnimation { - NumberAnimation { target: finger; property: "x"; to: editPosX - scoreHow.width * 0.05; duration: 500 } - NumberAnimation { target: finger; property: "y"; to: editPosY; duration: 500 } - } - ParallelAnimation { - NumberAnimation { target: finger; property: "x"; to: editPosX + scoreHow.width * 0.05; duration: 1000 } - NumberAnimation { target: finger; property: "y"; to: editPosY; duration: 1000 } - } - PauseAnimation { duration: 1000 } - ScriptAction { script: descView.currentIndex = 2 } // Move up and down - ParallelAnimation { - NumberAnimation { target: finger; property: "y"; to: editPosY - 10 * gotScore.scale; duration: 1200 } - NumberAnimation { target: gotScore.noteAdd; property: "yPos"; to: gotScore.upperLine - 6; duration: 1200 } - } - PauseAnimation { duration: 500 } - ParallelAnimation { - NumberAnimation { target: finger; property: "y"; to: editPosY + 8 * gotScore.scale; duration: 2000 } - NumberAnimation { target: gotScore.noteAdd; property: "yPos"; to: gotScore.upperLine + 12; duration: 2000 } - } - PauseAnimation { duration: 500 } - ParallelAnimation { - NumberAnimation { target: finger; property: "y"; to: editPosY + 2 * gotScore.scale; duration: 600 } - NumberAnimation { target: gotScore.noteAdd; property: "yPos"; to: gotScore.upperLine + 6; duration: 600 } - } - ScriptAction { script: descView.currentIndex = 3 } // Rise finger - PauseAnimation { duration: 1000 } - ScriptAction { script: gotScore.scoreToobox.active = true } - ParallelAnimation { - NumberAnimation { target: finger; property: "scale"; to: 4; duration: 500 } - NumberAnimation { target: finger; property: "x"; to: editPosX + scoreHow.width * 0.07; duration: 500 } - } - ScriptAction { script: descView.currentIndex = 4 } // select accidental - PauseAnimation { duration: 1000 } - ParallelAnimation { - NumberAnimation { target: finger; property: "scale"; to: 3; duration: 750 } - NumberAnimation { target: finger; property: "x"; to: boxPosX; duration: 750 } - NumberAnimation { target: finger; property: "y"; to: boxPosY; duration: 750 } + property real factor: gotScore.scoreToobox ? gotScore.scoreToobox.factor * 0.9 : NOO.isAndroid() ? NOO.shortScreenSide() * 0.036 : NOO.factor() * 1.08 + property real editPosX: gotScore.x + 23 * gotScore.scale + property real editPosY: gotScore.y + (gotScore.upperLine + 8) * gotScore.scale // upperLine + 4 + property real boxPosX: gotScore.x + 2 + factor * 2.5 + finger.width * 0.2 // in the middle of sharp control on score toolbox + property real boxPosY: (NOO.isAndroid() ? (height - factor * 27) / 2 : NOO.factor() / 2) + factor * 7.5 + finger.width * 0.2 + + function stop() { + gotAnim.running = false; } - ScriptAction { script: gotIt.setCursorAlter(1) } // select sharp - PauseAnimation { duration: 1000 } - ParallelAnimation { - NumberAnimation { target: finger; property: "scale"; to: 3; easing.type: Easing.OutBack; duration: 750 } - NumberAnimation { target: finger; property: "x"; to: boxPosX + factor * 2; easing.type: Easing.OutBack; duration: 750 } - NumberAnimation { target: finger; property: "y"; to: boxPosY + factor * 12; duration: 750 } + + function start() { + finger.opacity = 0; + finger.scale = 1; + finger.x = parent.width - finger.width; + finger.y = parent.height - finger.height; + gotScore.noteAdd.active = false; + gotScore.scoreToobox.active = false; + gotScore.clearScore(); + gotScore.noteAdd.yPos = 0; + gotIt.setCursorAlter(0); + gotIt.setWorkRtmValue(3); + descView.currentIndex = -1; + gotAnim.running = true; } - ScriptAction { script: gotIt.setWorkRtmValue(4) } // select eight - PauseAnimation { duration: 1000 } - ScriptAction { script: descView.currentIndex = 5 } // finally confirm note - ParallelAnimation { - NumberAnimation { target: finger; property: "scale"; to: 4; duration: 500 } - NumberAnimation { target: finger; property: "x"; to: boxPosX + (editPosX - boxPosX) / 2; duration: 500 } - NumberAnimation { target: finger; property: "y"; to: editPosY - gotScore.height * 0.2; duration: 500 } + + gotItType: TgotIt.GotHandleScore + visible: true + onClicked: close() + + Image { + id: finger + + z: 1050 // above everything and score toolbox + x: parent.width - width + y: parent.height - height + source: NOO.pix("fingerpoint") + width: parent.width * 0.05 + height: width + opacity: 0 } - ParallelAnimation { - NumberAnimation { target: finger; property: "scale"; to: 3; duration: 500 } - NumberAnimation { target: finger; property: "x"; to: editPosX; duration: 500 } - NumberAnimation { target: finger; property: "y"; to: editPosY; duration: 500 } + + // under score + Rectangle { + width: gotScore.width * 1.41 + height: width + radius: width / 2 + x: width * -0.25 + y: height * -0.25 + color: NOO.alpha(activPal.highlight, 50) } - ScriptAction { - script: { - gotScore.addNote(NOO.note(5, 1, 1, 4)) // add note to e score (g#1 eight) - gotScore.scoreToobox.active = false - gotScore.noteAdd.active = false - } + + // cover score mouse/touch actions + MouseArea { + anchors.fill: gotScore + z: 1049 + hoverEnabled: true } - PauseAnimation { duration: 150 } - ParallelAnimation { - NumberAnimation { target: finger; property: "scale"; to: 4; duration: 500 } - NumberAnimation { target: finger; property: "x"; to: scoreHow.width * 0.26; duration: 500 } - NumberAnimation { target: finger; property: "y"; to: scoreHow.height * 0.3; duration: 500 } + + Score { + id: gotScore + + height: parent.width * 0.35 + width: height * 1.1 + bgColor: "transparent" + enableKeySign: true + enableDoubleAccids: true + scoreObj.enableDoubleAccidentals: true + firstStaff.scale: height / firstStaff.linesCount + readOnly: false // HACK + scoreObj.editMode: true + scoreObj.allowAdding: visible + Component.onCompleted: gotIt.score = scoreObj } - ParallelAnimation { - NumberAnimation { target: finger; property: "x"; to: scoreHow.width * 0.32; duration: 500 } - NumberAnimation { target: finger; property: "y"; to: scoreHow.height * 0.39; duration: 500 } + + Rectangle { + width: parent.width * 0.59 + height: parent.height - NOO.factor() * 4 + x: parent.width * 0.41 + NOO.factor() + y: NOO.factor() + + Column { + anchors.horizontalCenter: parent.hozrizontalCenter + width: parent.width - NOO.factor() * 2 + spacing: NOO.factor() + + Text { + anchors.horizontalCenter: parent.hozrizontalCenter + color: activPal.text + text: qsTr("Editing score with touch") + + font { + bold: true + pixelSize: scoreHow.width * 0.03 + } + + } + + ListView { + id: descView + + currentIndex: -1 + clip: true + model: [qsTr("Touch and hold area of a note you want to edit."), qsTr("Move finger left or right to see edited note."), qsTr("Then move finger up or down to find desired note pitch."), qsTr("Rise the finger."), qsTr("If necessary, select accidental or rhythmic value."), qsTr("Finally, tap selected note shortly.")] + width: parent.width - NOO.factor() * 2 + height: parent.parent.height - scoreHow.width * 0.04 - NOO.factor() + spacing: NOO.factor() / 2 + + delegate: Text { + width: parent.width - NOO.factor() / 2 + text: index + 1 + ". " + modelData + color: activPal.text + wrapMode: Text.WordWrap + style: index === descView.currentIndex ? Text.Sunken : Text.Normal + styleColor: activPal.highlight + + font { + bold: index === descView.currentIndex + pixelSize: Math.max(scoreHow.width * 0.015, NOO.factor()) + } + + } + + } + + } + } - ParallelAnimation { - NumberAnimation { target: finger; property: "x"; to: scoreHow.width * 0.8; duration: 1000 } - NumberAnimation { target: finger; property: "y"; to: scoreHow.height * 0.8; duration: 1000 } + + // run animation with delay to allow initialize all properties + Timer { + running: true + interval: 250 + onTriggered: gotAnim.running = true } - ScriptAction { script: gotScore.noteAdd.visible = false } - PauseAnimation { duration: 1000 } - ScriptAction { script: descView.currentIndex = -1 } - } - - Row { - x: NOO.factor() * (NOO.isAndroid() ? 1 : 2); y: parent.height - height - NOO.factor() / 2 - spacing: NOO.factor() * (NOO.isAndroid() ? 1 : 3) - TcuteButton { - text: NOO.TR("QShortcut", gotAnim.running ? "Stop" : "Play") - width: height * 3.5; height: NOO.factor() * (NOO.isAndroid() ? 2 : 3) - font { pixelSize: height * 0.7; bold: true; capitalization: Font.AllUppercase } - onClicked: { - if (gotAnim.running) - scoreHow.stop() - else - scoreHow.start() - } + + SequentialAnimation { + id: gotAnim + + PauseAnimation { + duration: 500 + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "opacity" + to: 1 + } + + NumberAnimation { + target: finger + property: "scale" + to: 3 + easing.type: Easing.OutBack + duration: 1000 + } + + NumberAnimation { + target: finger + property: "x" + to: editPosX + duration: 1000 + } + + NumberAnimation { + target: finger + property: "y" + to: editPosY + easing.type: Easing.OutBack + duration: 1000 + } + + } + + ScriptAction { + script: { + descView.currentIndex = 0; // touch and hold + gotScore.noteAdd.visible = true; + gotScore.scoreToobox.active = false; + gotScore.noteAdd.active = true; + gotScore.noteAdd.yPos = gotScore.upperLine + 4; + } + } + + PauseAnimation { + duration: 1000 + } + // Move left or right + + ScriptAction { + script: descView.currentIndex = 1 + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "x" + to: editPosX - scoreHow.width * 0.05 + duration: 500 + } + + NumberAnimation { + target: finger + property: "y" + to: editPosY + duration: 500 + } + + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "x" + to: editPosX + scoreHow.width * 0.05 + duration: 1000 + } + + NumberAnimation { + target: finger + property: "y" + to: editPosY + duration: 1000 + } + + } + + PauseAnimation { + duration: 1000 + } + // Move up and down + + ScriptAction { + script: descView.currentIndex = 2 + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "y" + to: editPosY - 10 * gotScore.scale + duration: 1200 + } + + NumberAnimation { + target: gotScore.noteAdd + property: "yPos" + to: gotScore.upperLine - 6 + duration: 1200 + } + + } + + PauseAnimation { + duration: 500 + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "y" + to: editPosY + 8 * gotScore.scale + duration: 2000 + } + + NumberAnimation { + target: gotScore.noteAdd + property: "yPos" + to: gotScore.upperLine + 12 + duration: 2000 + } + + } + + PauseAnimation { + duration: 500 + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "y" + to: editPosY + 2 * gotScore.scale + duration: 600 + } + + NumberAnimation { + target: gotScore.noteAdd + property: "yPos" + to: gotScore.upperLine + 6 + duration: 600 + } + + } + // Rise finger + + ScriptAction { + script: descView.currentIndex = 3 + } + + PauseAnimation { + duration: 1000 + } + + ScriptAction { + script: gotScore.scoreToobox.active = true + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "scale" + to: 4 + duration: 500 + } + + NumberAnimation { + target: finger + property: "x" + to: editPosX + scoreHow.width * 0.07 + duration: 500 + } + + } + // select accidental + + ScriptAction { + script: descView.currentIndex = 4 + } + + PauseAnimation { + duration: 1000 + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "scale" + to: 3 + duration: 750 + } + + NumberAnimation { + target: finger + property: "x" + to: boxPosX + duration: 750 + } + + NumberAnimation { + target: finger + property: "y" + to: boxPosY + duration: 750 + } + + } + // select sharp + + ScriptAction { + script: gotIt.setCursorAlter(1) + } + + PauseAnimation { + duration: 1000 + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "scale" + to: 3 + easing.type: Easing.OutBack + duration: 750 + } + + NumberAnimation { + target: finger + property: "x" + to: boxPosX + factor * 2 + easing.type: Easing.OutBack + duration: 750 + } + + NumberAnimation { + target: finger + property: "y" + to: boxPosY + factor * 12 + duration: 750 + } + + } + // select eight + + ScriptAction { + script: gotIt.setWorkRtmValue(4) + } + + PauseAnimation { + duration: 1000 + } + // finally confirm note + + ScriptAction { + script: descView.currentIndex = 5 + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "scale" + to: 4 + duration: 500 + } + + NumberAnimation { + target: finger + property: "x" + to: boxPosX + (editPosX - boxPosX) / 2 + duration: 500 + } + + NumberAnimation { + target: finger + property: "y" + to: editPosY - gotScore.height * 0.2 + duration: 500 + } + + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "scale" + to: 3 + duration: 500 + } + + NumberAnimation { + target: finger + property: "x" + to: editPosX + duration: 500 + } + + NumberAnimation { + target: finger + property: "y" + to: editPosY + duration: 500 + } + + } + + ScriptAction { + script: { + gotScore.addNote(NOO.note(5, 1, 1, 4)); // add note to e score (g#1 eight) + gotScore.scoreToobox.active = false; + gotScore.noteAdd.active = false; + } + } + + PauseAnimation { + duration: 150 + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "scale" + to: 4 + duration: 500 + } + + NumberAnimation { + target: finger + property: "x" + to: scoreHow.width * 0.26 + duration: 500 + } + + NumberAnimation { + target: finger + property: "y" + to: scoreHow.height * 0.3 + duration: 500 + } + + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "x" + to: scoreHow.width * 0.32 + duration: 500 + } + + NumberAnimation { + target: finger + property: "y" + to: scoreHow.height * 0.39 + duration: 500 + } + + } + + ParallelAnimation { + NumberAnimation { + target: finger + property: "x" + to: scoreHow.width * 0.8 + duration: 1000 + } + + NumberAnimation { + target: finger + property: "y" + to: scoreHow.height * 0.8 + duration: 1000 + } + + } + + ScriptAction { + script: gotScore.noteAdd.visible = false + } + + PauseAnimation { + duration: 1000 + } + + ScriptAction { + script: descView.currentIndex = -1 + } + } - TcuteButton { - enabled: gotAnim.running - text: gotAnim.paused ? NOO.TR("QWizard", "Continue") : NOO.TR("QShortcut", "Pause") - width: height * 3.5; height: NOO.factor() * (NOO.isAndroid() ? 2 : 3) - font { pixelSize: height * 0.7; bold: true; capitalization: Font.AllUppercase } - onClicked: { - if (gotAnim.paused) - gotAnim.resume() - else - gotAnim.pause() - } + + Row { + x: NOO.factor() * (NOO.isAndroid() ? 1 : 2) + y: parent.height - height - NOO.factor() / 2 + spacing: NOO.factor() * (NOO.isAndroid() ? 1 : 3) + + TcuteButton { + text: NOO.TR("QShortcut", gotAnim.running ? "Stop" : "Play") + width: height * 3.5 + height: NOO.factor() * (NOO.isAndroid() ? 2 : 3) + onClicked: { + if (gotAnim.running) + scoreHow.stop(); + else + scoreHow.start(); + } + + font { + pixelSize: height * 0.7 + bold: true + capitalization: Font.AllUppercase + } + + } + + TcuteButton { + enabled: gotAnim.running + text: gotAnim.paused ? NOO.TR("QWizard", "Continue") : NOO.TR("QShortcut", "Pause") + width: height * 3.5 + height: NOO.factor() * (NOO.isAndroid() ? 2 : 3) + onClicked: { + if (gotAnim.paused) + gotAnim.resume(); + else + gotAnim.pause(); + } + + font { + pixelSize: height * 0.7 + bold: true + capitalization: Font.AllUppercase + } + + } + } - } + } diff --git a/src/qml/gotit/ImportInfo.qml b/src/qml/gotit/ImportInfo.qml index ce2da6fc19794354788db6043ac4ea00a55b96fa..1e5a77d6ed3ee7f900b85b962b22a2ecf6ce84c3 100644 --- a/src/qml/gotit/ImportInfo.qml +++ b/src/qml/gotit/ImportInfo.qml @@ -2,72 +2,101 @@ * 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 Nootka 1.0 import Nootka.Main 1.0 -import "../" - +import QtQuick 2.12 GotIt { - id: gotImport - gotItType: TgotIt.GotImportScore - visible: true - - onClicked: { - if (showGotIt) { // Got It, not help dialog - if (!remaindChecked) // store only if user doesn't want it next time - GLOB.setGotIt("ScoreImport", false) - } - close() - destroy() - } - - background: Rectangle { - gradient: Gradient { - GradientStop { position: 0.0; color: NOO.alpha(activPal.base, 150) } - GradientStop { position: textTop / gotImport.height - 0.1; color: NOO.alpha(activPal.base, 150) } - GradientStop { position: textTop / gotImport.height + 0.05; color: Qt.tint(activPal.base, NOO.alpha("green", 50)) } + id: gotImport + + // private + property real textTop: gotImport.height - Math.min(impCol.height + NOO.factor() * (NOO.isAndroid() ? 3 : 9), gotImport.height * 0.7) + + gotItType: TgotIt.GotImportScore + visible: true + onClicked: { + if (showGotIt) { + // store only if user doesn't want it next time + + // Got It, not help dialog + if (!remaindChecked) + GLOB.setGotIt("ScoreImport", false); + + } + close(); + destroy(); } - } - - // private - property real textTop: gotImport.height - Math.min(impCol.height + NOO.factor() * (NOO.isAndroid() ? 3 : 9), gotImport.height * 0.7) - Tflickable { - width: parent.width; height: parent.height * 0.7 - y: textTop - contentHeight: impCol.height + NOO.factor() * 4; contentWidth: width - - Column { - id: impCol - spacing: NOO.factor(); leftPadding: NOO.factor() - width: parent.width - NOO.factor() * 13 - Text { - width: parent.width - wrapMode: Text.WordWrap - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - text: qsTr("Unfortunately Nootka cannot display all notes of this score at once.") - color: activPal.text - font { bold: true; pixelSize: NOO.factor() * 1.5 } - } - Text { - width: parent.width - wrapMode: Text.WordWrap - text: qsTr("But you can select here some voice or a part and import it to the application.") + "<br>" - + qsTr("Before that, you can transform (split, transpose and etc.) score parts and also select which note of a chord will be imported.") - + "<br>" + qsTr("Voices are divided automatically when meter, clef or key changes.") - color: activPal.text - font.pixelSize: NOO.factor() * 1.1 - } - Text { + + Tflickable { width: parent.width - wrapMode: Text.WordWrap - text: qsTr("When you are preparing an exam or an exercise from the score parts, more fragments can be imported at once.") - color: activPal.text - font.pixelSize: NOO.factor() * 1.1 - } + height: parent.height * 0.7 + y: textTop + contentHeight: impCol.height + NOO.factor() * 4 + contentWidth: width + + Column { + id: impCol + + spacing: NOO.factor() + leftPadding: NOO.factor() + width: parent.width - NOO.factor() * 13 + + Text { + width: parent.width + wrapMode: Text.WordWrap + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + text: qsTr("Unfortunately Nootka cannot display all notes of this score at once.") + color: activPal.text + + font { + bold: true + pixelSize: NOO.factor() * 1.5 + } + + } + + Text { + width: parent.width + wrapMode: Text.WordWrap + text: qsTr("But you can select here some voice or a part and import it to the application.") + "<br>" + qsTr("Before that, you can transform (split, transpose and etc.) score parts and also select which note of a chord will be imported.") + "<br>" + qsTr("Voices are divided automatically when meter, clef or key changes.") + color: activPal.text + font.pixelSize: NOO.factor() * 1.1 + } + + Text { + width: parent.width + wrapMode: Text.WordWrap + text: qsTr("When you are preparing an exam or an exercise from the score parts, more fragments can be imported at once.") + color: activPal.text + font.pixelSize: NOO.factor() * 1.1 + } + + } + + } + + background: Rectangle { + + gradient: Gradient { + GradientStop { + position: 0 + color: NOO.alpha(activPal.base, 150) + } + + GradientStop { + position: textTop / gotImport.height - 0.1 + color: NOO.alpha(activPal.base, 150) + } + + GradientStop { + position: textTop / gotImport.height + 0.05 + color: Qt.tint(activPal.base, NOO.alpha("green", 50)) + } + + } + } - } } diff --git a/src/qml/gotit/NoteSelected.qml b/src/qml/gotit/NoteSelected.qml index 26dbece1d0aa29e299b8cc214821abee37a319bd..b77acc23792190d12af6b81ddf67df9b31fb7733 100644 --- a/src/qml/gotit/NoteSelected.qml +++ b/src/qml/gotit/NoteSelected.qml @@ -2,197 +2,286 @@ * 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 1.0 import Nootka.Main 1.0 -import "../score" -import "../" - +import QtQuick 2.12 GotIt { - id: selectHow - gotItType: TgotIt.GotNoteSelected - visible: true - - onClicked: { - if (showGotIt) { // Got It, not help dialog - if (!remaindChecked) // store only if user doesn't want it next time - GLOB.setGotIt("noteSelected", false) - SOUND.startListen() + id: selectHow + + property int noSelCnt: 1 + property int restAt: 4 + + function stop() { + selAnim.running = false; + noSelAnim.running = false; + noSelScore.noteAdd.hiTimer.running = false; } - close() - destroy() - } - - function stop() { - selAnim.running = false - noSelAnim.running = false - noSelScore.noteAdd.hiTimer.running = false - } - - function start() { - selAnim.running = true - noSelAnim.running = true - noSelScore.noteAdd.hiTimer.running = true - } - - property int noSelCnt: 1 - property int restAt: 4 - - Tflickable { - anchors.fill: parent - contentHeight: selCol.height + NOO.factor() * 10 - Column { - id: selCol - width: parent.width; spacing: NOO.factor() / 2 - - Text { - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text - font { bold: true; pixelSize: selectHow.width * 0.03 } - text: qsTr("Note selection and playing") - } - Tile { - id: selectedTile - anchors { horizontalCenter: undefined; right: parent.right } - width: parent.width * (NOO.isAndroid() ? 1 : 0.9) - height: selText.height + selScore.height * 0.7 - bgBorder { color: activPal.highlight; width: 2 } - bgColor: Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 20)) - - Score { - id: selScore - anchors.horizontalCenter: parent.horizontalCenter - y: -height * (NOO.isAndroid() ? 0.25 : 0.1) - height: selectHow.width * 0.3; width: parent.width * 0.8 - bgColor: "transparent"; editText.visible: false - readOnly: false; scoreObj.editMode: true; scoreObj.allowAdding: visible // HACK - Component.onCompleted: { - for (var n = 1; n < 8; ++n) - addNote(NOO.note(n, 1, 0, (n < 2 ? 3 : 4))) - currentNote = scoreObj.note(5) - } - Rectangle { // note highlight - id: noteHighlight - parent: selScore.currentNote - width: selScore.currentNote ? selScore.currentNote.width * 1.5 : 0 - height: selScore.currentNote ? Math.min(14.0, selScore.currentNote.notePosY + 8.0) : 0 - x: selScore.currentNote ? -width * 0.25 : 0 - y: selScore.currentNote ? Math.min(selScore.currentNote.height - height, Math.max(0.0, selScore.currentNote.notePosY - height / 2.0)) : 0 - color: NOO.alpha(activPal.highlight, 75) - z: -1 - radius: width / 3.0 - } - Text { - parent: selScore.noteAdd - x: parent ? (parent.width - width) / 2 : 0; y: 14 - height * scale - text: gotIt.noteCursorText() - horizontalAlignment: Text.AlignHCenter - color: GLOB.noteCursorColor - font { pixelSize: 10; bold: true } - scale: 0.2; transformOrigin: Item.Top - } - MouseArea { // cover score mouse/touch actions - anchors.fill: parent - z: 1049 - hoverEnabled: true - } - SequentialAnimation { - id: selAnim - loops: Animation.Infinite - ScriptAction { - script: selScore.setNote(5, NOO.note(1 + Math.random() * 7, 1 + Math.random() * 2, -1 + noSelCnt % 3, 4)) - } - PauseAnimation { duration: 1500 } - } - } - Text { - id: selText - anchors.horizontalCenter: parent.horizontalCenter - y: selScore.height * 0.55; width: parent.width * (NOO.isAndroid() ? 0.9 : 0.7) - color: activPal.text - text: gotIt.ifSelectedText() - wrapMode: Text.WordWrap; font.pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.2) - } - } - Tile { - width: selectHow.width * (NOO.isAndroid() ? 0.9: 0.6) - Text { - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text - width: parent.width - NOO.factor(); leftPadding: NOO.factor() - text: gotIt.unselectText() - wrapMode: Text.WordWrap; font.pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.2) + function start() { + selAnim.running = true; + noSelAnim.running = true; + noSelScore.noteAdd.hiTimer.running = true; + } + + gotItType: TgotIt.GotNoteSelected + visible: true + onClicked: { + if (showGotIt) { + // store only if user doesn't want it next time + + // Got It, not help dialog + if (!remaindChecked) + GLOB.setGotIt("noteSelected", false); + + SOUND.startListen(); } - } - Tile { - id: noSelTile - width: parent.width * (NOO.isAndroid() ? 1 : 0.9) - height: noSelText.height + noSelScore.height * 0.7 - anchors.horizontalCenter: undefined - bgBorder { color: activPal.text; width: 2 } - bgColor: activPal.base - - Score { - id: noSelScore - anchors.horizontalCenter: parent.horizontalCenter - y: -height * (NOO.isAndroid() ? 0.25 : 0.1) - height: selectHow.width * 0.3; width: parent.width * 0.8 - bgColor: "transparent"; editText.visible: false - readOnly: false; scoreObj.editMode: true; scoreObj.allowAdding: visible - Text { - parent: noSelScore.noteAdd - x: parent ? (parent.width - width) / 2 : 0; y: 14 - height * scale - text: gotIt.noteCursorText() - horizontalAlignment: Text.AlignHCenter - color: GLOB.noteCursorColor - font { pixelSize: 10; bold: true } - scale: 0.2; transformOrigin: Item.Top - } - MouseArea { - anchors.fill: parent - z: 1049 - hoverEnabled: true - } - SequentialAnimation { - id: noSelAnim - loops: Animation.Infinite - ScriptAction { - script: { - noSelScore.addNote(NOO.note(noSelCnt, 1, 0, 3 + Math.random() * 3, noSelCnt === restAt)) - noSelCnt++ - if (noSelCnt > 8) { - noSelScore.clearScore() - noSelCnt = 1 - restAt = Math.random() * 8 + close(); + destroy(); + } + + Tflickable { + anchors.fill: parent + contentHeight: selCol.height + NOO.factor() * 10 + + Column { + id: selCol + + width: parent.width + spacing: NOO.factor() / 2 + + Text { + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + text: qsTr("Note selection and playing") + + font { + bold: true + pixelSize: selectHow.width * 0.03 } - } + } - PauseAnimation { duration: 1000 } - } - } - Text { - id: noSelText - anchors.horizontalCenter: parent.horizontalCenter - y: noSelScore.height * 0.55; width: parent.width * (NOO.isAndroid() ? 0.9 : 0.7) - color: activPal.text - text: gotIt.ifNotSelectedText() - wrapMode: Text.WordWrap; font.pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.2) + + Tile { + id: selectedTile + + width: parent.width * (NOO.isAndroid() ? 1 : 0.9) + height: selText.height + selScore.height * 0.7 + bgColor: Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 20)) + + anchors { + horizontalCenter: undefined + right: parent.right + } + + bgBorder { + color: activPal.highlight + width: 2 + } + + Score { + id: selScore + + anchors.horizontalCenter: parent.horizontalCenter + y: -height * (NOO.isAndroid() ? 0.25 : 0.1) + height: selectHow.width * 0.3 + width: parent.width * 0.8 + bgColor: "transparent" + editText.visible: false + readOnly: false // HACK + scoreObj.editMode: true + scoreObj.allowAdding: visible + Component.onCompleted: { + for (var n = 1; n < 8; ++n) addNote(NOO.note(n, 1, 0, (n < 2 ? 3 : 4))) + currentNote = scoreObj.note(5); + } + + // note highlight + Rectangle { + id: noteHighlight + + parent: selScore.currentNote + width: selScore.currentNote ? selScore.currentNote.width * 1.5 : 0 + height: selScore.currentNote ? Math.min(14, selScore.currentNote.notePosY + 8) : 0 + x: selScore.currentNote ? -width * 0.25 : 0 + y: selScore.currentNote ? Math.min(selScore.currentNote.height - height, Math.max(0, selScore.currentNote.notePosY - height / 2)) : 0 + color: NOO.alpha(activPal.highlight, 75) + z: -1 + radius: width / 3 + } + + Text { + parent: selScore.noteAdd + x: parent ? (parent.width - width) / 2 : 0 + y: 14 - height * scale + text: gotIt.noteCursorText() + horizontalAlignment: Text.AlignHCenter + color: GLOB.noteCursorColor + scale: 0.2 + transformOrigin: Item.Top + + font { + pixelSize: 10 + bold: true + } + + } + // cover score mouse/touch actions + + MouseArea { + anchors.fill: parent + z: 1049 + hoverEnabled: true + } + + SequentialAnimation { + id: selAnim + + loops: Animation.Infinite + + ScriptAction { + script: selScore.setNote(5, NOO.note(1 + Math.random() * 7, 1 + Math.random() * 2, -1 + noSelCnt % 3, 4)) + } + + PauseAnimation { + duration: 1500 + } + + } + + } + + Text { + id: selText + + anchors.horizontalCenter: parent.horizontalCenter + y: selScore.height * 0.55 + width: parent.width * (NOO.isAndroid() ? 0.9 : 0.7) + color: activPal.text + text: gotIt.ifSelectedText() + wrapMode: Text.WordWrap + font.pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.2) + } + + } + + Tile { + width: selectHow.width * (NOO.isAndroid() ? 0.9 : 0.6) + + Text { + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + width: parent.width - NOO.factor() + leftPadding: NOO.factor() + text: gotIt.unselectText() + wrapMode: Text.WordWrap + font.pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.2) + } + + } + + Tile { + id: noSelTile + + width: parent.width * (NOO.isAndroid() ? 1 : 0.9) + height: noSelText.height + noSelScore.height * 0.7 + anchors.horizontalCenter: undefined + bgColor: activPal.base + + bgBorder { + color: activPal.text + width: 2 + } + + Score { + id: noSelScore + + anchors.horizontalCenter: parent.horizontalCenter + y: -height * (NOO.isAndroid() ? 0.25 : 0.1) + height: selectHow.width * 0.3 + width: parent.width * 0.8 + bgColor: "transparent" + editText.visible: false + readOnly: false + scoreObj.editMode: true + scoreObj.allowAdding: visible + + Text { + parent: noSelScore.noteAdd + x: parent ? (parent.width - width) / 2 : 0 + y: 14 - height * scale + text: gotIt.noteCursorText() + horizontalAlignment: Text.AlignHCenter + color: GLOB.noteCursorColor + scale: 0.2 + transformOrigin: Item.Top + + font { + pixelSize: 10 + bold: true + } + + } + + MouseArea { + anchors.fill: parent + z: 1049 + hoverEnabled: true + } + + SequentialAnimation { + id: noSelAnim + + loops: Animation.Infinite + + ScriptAction { + script: { + noSelScore.addNote(NOO.note(noSelCnt, 1, 0, 3 + Math.random() * 3, noSelCnt === restAt)); + noSelCnt++; + if (noSelCnt > 8) { + noSelScore.clearScore(); + noSelCnt = 1; + restAt = Math.random() * 8; + } + } + } + + PauseAnimation { + duration: 1000 + } + + } + + } + + Text { + id: noSelText + + anchors.horizontalCenter: parent.horizontalCenter + y: noSelScore.height * 0.55 + width: parent.width * (NOO.isAndroid() ? 0.9 : 0.7) + color: activPal.text + text: gotIt.ifNotSelectedText() + wrapMode: Text.WordWrap + font.pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.2) + } + + } + } - } + } - } - - Timer { - running: true - interval: 500 - onTriggered: { - selAnim.running = true - noSelAnim.running = true - noSelScore.noteAdd.hiTimer.running = true + + Timer { + running: true + interval: 500 + onTriggered: { + selAnim.running = true; + noSelAnim.running = true; + noSelScore.noteAdd.hiTimer.running = true; + } } - } } diff --git a/src/qml/gotit/SoundInfo.qml b/src/qml/gotit/SoundInfo.qml index f7533ab650b71acdd461e823ad6a55091de1ab59..b2725eddeaa9f8148527cdd140f01d92b9853036 100644 --- a/src/qml/gotit/SoundInfo.qml +++ b/src/qml/gotit/SoundInfo.qml @@ -2,154 +2,241 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - -import Nootka 1.0 -import Nootka.Main 1.0 import "../" import "../sound" +import Nootka 1.0 +import Nootka.Main 1.0 +import QtQuick 2.12 GotIt { - gotItType: TgotIt.GotSoundInfo - visible: true - - onClicked: close() - - Tflickable { - height: parent.height - contentHeight: sCol.height + NOO.factor() * 10 - contentWidth: width - - Column { - id: sCol - width: parent.width - NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() - Item { width: NOO.factor() * 10; height: NOO.factor(); visible: !NOO.isAndroid() } - TipRect { - width: sCol.width - NOO.factor(); height: headRow.height + NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 100)) - Row { - id: headRow - spacing: NOO.factor() * 2 - anchors.centerIn: parent - Text { - font { family: "Nootka"; pixelSize: NOO.factor() * 5 } - color: activPal.highlight - text: "r"; rotation: 180 - } - LinkText { - anchors.verticalCenter: parent.verticalCenter - font { bold: true; pixelSize: NOO.factor() * 2 } - text: qsTr("Nootka can hear You!") - } - Text { - font { family: "Nootka"; pixelSize: NOO.factor() * 5 } - color: activPal.highlight - text: "r" - } - } - } - Text { - width: parent.width * 0.96; wrapMode: Text.WordWrap - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text; textFormat: Text.StyledText - lineHeight: NOO.isAndroid() ? 1 : 1.5 - text: "<br>" - + qsTr("Nootka recognizes played sounds and theirs duration (rhythms). But to achieve accurate results it requires some preparations and a little patience. Here are some clues:") - } - Repeater { - model: [ qsTr("Be sure your system is able to record what are you playing."), - qsTr("Adjust minimal note volume a little below of your input volume level.") ] - Row { + gotItType: TgotIt.GotSoundInfo + visible: true + onClicked: close() + + Tflickable { + height: parent.height + contentHeight: sCol.height + NOO.factor() * 10 + contentWidth: width + + Column { + id: sCol + + width: parent.width - NOO.factor() anchors.horizontalCenter: parent.horizontalCenter spacing: NOO.factor() - Rectangle { - anchors.verticalCenter: parent.verticalCenter - width: NOO.factor() * 0.7; height: width; radius: width / 2 - color: activPal.text + + Item { + width: NOO.factor() * 10 + height: NOO.factor() + visible: !NOO.isAndroid() } - Text { - width: sCol.width * 0.96 - NOO.factor() * 2; wrapMode: Text.WordWrap - color: activPal.text; textFormat: Text.StyledText - text: modelData + + TipRect { + width: sCol.width - NOO.factor() + height: headRow.height + NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + color: Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 100)) + + Row { + id: headRow + + spacing: NOO.factor() * 2 + anchors.centerIn: parent + + Text { + color: activPal.highlight + text: "r" + rotation: 180 + + font { + family: "Nootka" + pixelSize: NOO.factor() * 5 + } + + } + + LinkText { + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Nootka can hear You!") + + font { + bold: true + pixelSize: NOO.factor() * 2 + } + + } + + Text { + color: activPal.highlight + text: "r" + + font { + family: "Nootka" + pixelSize: NOO.factor() * 5 + } + + } + + } + } - } - } - Text { - width: parent.width * 0.8; wrapMode: Text.WordWrap - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text; textFormat: Text.StyledText - horizontalAlignment: Text.AlignHCenter - text: qsTr("Play a few sounds to figure out their maximal volume,<br>then set level knob about 10-20% below.") - } - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() - TipRect { - color: activPal.base - width: NOO.factor() * 4; height: NOO.factor() * 2.5 + Text { - anchors.horizontalCenter: parent.horizontalCenter - y: height * -0.25 - color: activPal.text - font { family: "Scorek"; pixelSize: NOO.factor() * 2 } - text: gotIt.noteName + width: parent.width * 0.96 + wrapMode: Text.WordWrap + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + textFormat: Text.StyledText + lineHeight: NOO.isAndroid() ? 1 : 1.5 + text: "<br>" + qsTr("Nootka recognizes played sounds and theirs duration (rhythms). But to achieve accurate results it requires some preparations and a little patience. Here are some clues:") } - } - TipRect { - color: activPal.window - width: Math.min(NOO.factor() * 42, sCol.width * 0.98 - NOO.factor() * 10); height: NOO.factor() * 2.5 - VolumeBar { - id: volBar - anchors.centerIn: parent - width: Math.min(NOO.factor() * 40, parent.width * 0.9); height: NOO.factor() * 2 - knobVisible: true - Timer { - repeat: true; interval: 75; running: true - onTriggered: volBar.volume = SOUND.inputVol() - } + + Repeater { + model: [qsTr("Be sure your system is able to record what are you playing."), qsTr("Adjust minimal note volume a little below of your input volume level.")] + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() + + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: NOO.factor() * 0.7 + height: width + radius: width / 2 + color: activPal.text + } + + Text { + width: sCol.width * 0.96 - NOO.factor() * 2 + wrapMode: Text.WordWrap + color: activPal.text + textFormat: Text.StyledText + text: modelData + } + + } + } - } - TipRect { - color: activPal.base - width: NOO.factor() * 4; height: NOO.factor() * 2.5 + Text { - anchors.centerIn: parent - color: activPal.text - font.bold: true - text: gotIt.maxVolume + "%" + width: parent.width * 0.8 + wrapMode: Text.WordWrap + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + textFormat: Text.StyledText + horizontalAlignment: Text.AlignHCenter + text: qsTr("Play a few sounds to figure out their maximal volume,<br>then set level knob about 10-20% below.") } - } - } - Text { - visible: NOO.isAndroid() - width: parent.width * 0.8; wrapMode: Text.WordWrap - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text; textFormat: Text.StyledText - horizontalAlignment: Text.AlignHCenter - text: qsTr("Later, you can adjust the volume level in Nootka tuner window.<br>Invoke it from main menu or use any volume key.") - } - Item { width: NOO.factor() * 10; height: NOO.factor() } - Repeater { - model: [ qsTr("Aim to play loud and clear and avoid dirty sounds specific to your instrument."), - qsTr("If you want Nootka to write your melody with rhythm then you have to play exactly in selected tempo - preferably with a metronome. But during practice, when you are playing melody given by the application, the tempo can be at will unless some level defines it.") ] - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() - Rectangle { - anchors.verticalCenter: parent.verticalCenter - width: NOO.factor() * 0.7; height: width; radius: width / 2 - color: activPal.text + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() + + TipRect { + color: activPal.base + width: NOO.factor() * 4 + height: NOO.factor() * 2.5 + + Text { + anchors.horizontalCenter: parent.horizontalCenter + y: height * -0.25 + color: activPal.text + text: gotIt.noteName + + font { + family: "Scorek" + pixelSize: NOO.factor() * 2 + } + + } + + } + + TipRect { + color: activPal.window + width: Math.min(NOO.factor() * 42, sCol.width * 0.98 - NOO.factor() * 10) + height: NOO.factor() * 2.5 + + VolumeBar { + id: volBar + + anchors.centerIn: parent + width: Math.min(NOO.factor() * 40, parent.width * 0.9) + height: NOO.factor() * 2 + knobVisible: true + + Timer { + repeat: true + interval: 75 + running: true + onTriggered: volBar.volume = SOUND.inputVol() + } + + } + + } + + TipRect { + color: activPal.base + width: NOO.factor() * 4 + height: NOO.factor() * 2.5 + + Text { + anchors.centerIn: parent + color: activPal.text + font.bold: true + text: gotIt.maxVolume + "%" + } + + } + } + Text { - width: sCol.width * 0.96 - NOO.factor() * 2; wrapMode: Text.WordWrap - color: activPal.text; textFormat: Text.StyledText - text: modelData + visible: NOO.isAndroid() + width: parent.width * 0.8 + wrapMode: Text.WordWrap + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + textFormat: Text.StyledText + horizontalAlignment: Text.AlignHCenter + text: qsTr("Later, you can adjust the volume level in Nootka tuner window.<br>Invoke it from main menu or use any volume key.") } - } + + Item { + width: NOO.factor() * 10 + height: NOO.factor() + } + + Repeater { + model: [qsTr("Aim to play loud and clear and avoid dirty sounds specific to your instrument."), qsTr("If you want Nootka to write your melody with rhythm then you have to play exactly in selected tempo - preferably with a metronome. But during practice, when you are playing melody given by the application, the tempo can be at will unless some level defines it.")] + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() + + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: NOO.factor() * 0.7 + height: width + radius: width / 2 + color: activPal.text + } + + Text { + width: sCol.width * 0.96 - NOO.factor() * 2 + wrapMode: Text.WordWrap + color: activPal.text + textFormat: Text.StyledText + text: modelData + } + + } + + } + } - } - } + + } + } diff --git a/src/qml/instruments/Bandoneon.qml b/src/qml/instruments/Bandoneon.qml index cf4af7bdf1a4ec4a1968d908baf3a241cdf154d5..33cd61b8f70793ee23b218bf8789fc0035e1c050 100644 --- a/src/qml/instruments/Bandoneon.qml +++ b/src/qml/instruments/Bandoneon.qml @@ -2,226 +2,282 @@ * 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 Nootka 1.0 -import "../" +TbandoneonBg { + id: instrItem + // private + property int hiId: -1 + property var correctAnim: null + property var bandoZoom: null -TbandoneonBg { - id: instrItem - - width: Math.max(factor * 480, nootkaWindow.width) - height: GLOB.instrument.getItemHeight(nootkaWindow.shortEdge) - factor: height / 100 - - // private - property int hiId: -1 - property var correctAnim: null - property var bandoZoom: null - - transformOrigin: Item.TopLeft - Behavior on scale { - enabled: GLOB.useAnimations - NumberAnimation { - duration: 150 - onRunningChanged: { - if (bandoZoom && !running && scale > 1) - instrFlick.contentX = bandoZoom.flickX - } - } - } - - onCorrectInstrument: { - if (!correctAnim) - correctAnim = Qt.createComponent("qrc:/exam/CorrectInstrAnim.qml").createObject(instrItem) - correctAnim.doCross = wrongItem === null - correctAnim.start() - } - - Rectangle { - visible: sideHighlight !== TbandoneonBg.HighlightNone - color: GLOB.correctColor - width: factor * 207; height: factor * 20 - x: xOffset + (sideHighlight === TbandoneonBg.HighlightRight ? factor * 240 : factor * 10) - y: parent.height - height - } - - Image { - source: NOO.pix("bando-bg") - width: factor * 220; height: width * (sourceSize.height / sourceSize.width) - x: mainRow.x - z: 1 - } - Image { - source: NOO.pix("bando-bg") - width: factor * 220; height: width * (sourceSize.height / sourceSize.width) - x: mainRow.x + factor * 240 - z: 2 - } - - Row { - x: (parent.width * 0.985 - width) / 2 - y: factor * 2 - spacing: factor * 2 - Text { - anchors.verticalCenter: parent.verticalCenter - text: opening ? "\uE610" : (closing ? "\uE612" : "") - color: opening ? "blue" : "#FF00FF" - font { family: "Nootka"; pixelSize: factor * 20 } + width: Math.max(factor * 480, nootkaWindow.width) + height: GLOB.instrument.getItemHeight(nootkaWindow.shortEdge) + factor: height / 100 + transformOrigin: Item.TopLeft + onCorrectInstrument: { + if (!correctAnim) + correctAnim = Qt.createComponent("qrc:/exam/CorrectInstrAnim.qml").createObject(instrItem); + + correctAnim.doCross = wrongItem === null; + correctAnim.start(); } - Text { - anchors.verticalCenter: parent.verticalCenter - text: opening ? "(<b>A</b>)" : (closing ? "(<b>C</b>)" : "") - color: opening ? "blue" : "#FF00FF" - font { pixelSize: factor * 12 } + rightX: factor * 240 + xOffset: mainRow.x + Component.onCompleted: { + if (NOO.isAndroid() && NOO.fingerPixels() * 4 > height) + bandoZoom = Qt.createComponent("qrc:/instruments/InstrumentZoom.qml").createObject(instrItem); + } - } - - rightX: factor * 240 - xOffset: mainRow.x - - Row { - id: mainRow - anchors.horizontalCenter: parent.horizontalCenter - height: factor * 100 - z: 5 - Item { - height: parent.height; width: factor * 220 - Repeater { - model: 33 - Image { - source: NOO.pix("bando-button") - sourceSize.width: Math.round(parent.height / 6.5) - x: xAt(index) * factor * 1.1 - y: yAt(index) * factor * 1.2 + width * 0.25 - MouseArea { - anchors.fill: parent - hoverEnabled: !NOO.isAndroid() - onEntered: hiId = index - onExited: hiId = -1 - onClicked: { - if (!openButt.checked && !closeButt.checked) - opening = true - currentIndex = index - } - } + onWantNoteName: { + if (!extraName) { + extraName = Qt.createComponent("qrc:/instruments/ExtraName.qml").createObject(instrItem); + extraName.fSize = Qt.binding(function() { + return factor * 25; + }); + } + if (origin) { + extraName.text = name; + extraName.x = Qt.binding(function() { + return origin ? origin.x + (origin.width - extraName.width) / 2 : 0; + }); + extraName.y = Qt.binding(function() { + return origin ? origin.y - (origin.y > instrItem.height / 2.5 ? 60 : 10) * factor : 0; + }); + } else { + extraName.text = ""; } - } } - Column { - id: buttonCol - anchors.bottom: parent.bottom - spacing: factor * 4 - bottomPadding: factor * 4 - - TcuteButton { - id: openButt - width: factor * 20; height: factor * 15 - checked: opening - checkable: true - text: "\uE610"; font { family: "Nootka"; pixelSize: height } - color: openButt.checked ? "blue" : "gray" - hoverEnabled: !NOO.isAndroid() - onHoveredChanged: { - if (hovered) - NOO.setStatusTip("<big><span style=\"font-family: 'Nootka';\">\uE610</span></big> (<b>A</b>) - " - + qsTr("Bellows is opening.", - "Check please what bandoneon/accordion bellows does in your language. It may be more sophisticated word than 'opening'"), - Item.Top, true) - else - NOO.setStatusTip("", Item.Top) + Rectangle { + visible: sideHighlight !== TbandoneonBg.HighlightNone + color: GLOB.correctColor + width: factor * 207 + height: factor * 20 + x: xOffset + (sideHighlight === TbandoneonBg.HighlightRight ? factor * 240 : factor * 10) + y: parent.height - height + } + + Image { + source: NOO.pix("bando-bg") + width: factor * 220 + height: width * (sourceSize.height / sourceSize.width) + x: mainRow.x + z: 1 + } + + Image { + source: NOO.pix("bando-bg") + width: factor * 220 + height: width * (sourceSize.height / sourceSize.width) + x: mainRow.x + factor * 240 + z: 2 + } + + Row { + x: (parent.width * 0.985 - width) / 2 + y: factor * 2 + spacing: factor * 2 + + Text { + anchors.verticalCenter: parent.verticalCenter + text: opening ? "\uE610" : (closing ? "\uE612" : "") + color: opening ? "blue" : "#FF00FF" + + font { + family: "Nootka" + pixelSize: factor * 20 + } + } - onClicked: { - opening = openButt.checked - if (opening) - closing = false + + Text { + anchors.verticalCenter: parent.verticalCenter + text: opening ? "(<b>A</b>)" : (closing ? "(<b>C</b>)" : "") + color: opening ? "blue" : "#FF00FF" + + font { + pixelSize: factor * 12 + } + } - } - TcuteButton { - id: closeButt - width: factor * 20; height: factor * 15 - checked: closing - text: "\uE612"; font { family: "Nootka"; pixelSize: height } - checkable: true - color: closeButt.checked ? "#FF00FF" : "gray" - hoverEnabled: !NOO.isAndroid() - onHoveredChanged: { - if (hovered) - NOO.setStatusTip("<big><span style=\"font-family: 'Nootka';\">\uE612</span></big> (<b>C</b>) - " - + qsTr("Bellows is closing.", - "Check please what bandoneon/accordion bellows does in your language. It may be more sophisticated word than 'closing'"), - Item.Top, true) - else - NOO.setStatusTip("", Item.Top) + + } + + Row { + id: mainRow + + anchors.horizontalCenter: parent.horizontalCenter + height: factor * 100 + z: 5 + + Item { + height: parent.height + width: factor * 220 + + Repeater { + model: 33 + + Image { + source: NOO.pix("bando-button") + sourceSize.width: Math.round(parent.height / 6.5) + x: xAt(index) * factor * 1.1 + y: yAt(index) * factor * 1.2 + width * 0.25 + + MouseArea { + anchors.fill: parent + hoverEnabled: !NOO.isAndroid() + onEntered: hiId = index + onExited: hiId = -1 + onClicked: { + if (!openButt.checked && !closeButt.checked) + opening = true; + + currentIndex = index; + } + } + + } + + } + } - onClicked: { - closing = closeButt.checked - if (closing) - opening = false + + Column { + id: buttonCol + + anchors.bottom: parent.bottom + spacing: factor * 4 + bottomPadding: factor * 4 + + TcuteButton { + id: openButt + + width: factor * 20 + height: factor * 15 + checked: opening + checkable: true + text: "\uE610" + color: openButt.checked ? "blue" : "gray" + hoverEnabled: !NOO.isAndroid() + onHoveredChanged: { + if (hovered) + NOO.setStatusTip("<big><span style=\"font-family: 'Nootka';\">\uE610</span></big> (<b>A</b>) - " + qsTr("Bellows is opening.", "Check please what bandoneon/accordion bellows does in your language. It may be more sophisticated word than 'opening'"), Item.Top, true); + else + NOO.setStatusTip("", Item.Top); + } + onClicked: { + opening = openButt.checked; + if (opening) + closing = false; + + } + + font { + family: "Nootka" + pixelSize: height + } + + } + + TcuteButton { + id: closeButt + + width: factor * 20 + height: factor * 15 + checked: closing + text: "\uE612" + checkable: true + color: closeButt.checked ? "#FF00FF" : "gray" + hoverEnabled: !NOO.isAndroid() + onHoveredChanged: { + if (hovered) + NOO.setStatusTip("<big><span style=\"font-family: 'Nootka';\">\uE612</span></big> (<b>C</b>) - " + qsTr("Bellows is closing.", "Check please what bandoneon/accordion bellows does in your language. It may be more sophisticated word than 'closing'"), Item.Top, true); + else + NOO.setStatusTip("", Item.Top); + } + onClicked: { + closing = closeButt.checked; + if (closing) + opening = false; + + } + + font { + family: "Nootka" + pixelSize: height + } + + } + } - } - } - Item { - height: parent.height; width: factor * 230 - Repeater { - model: 38 - Image { - source: NOO.pix("bando-button") - sourceSize.width: Math.round(parent.height / 6.5) - x: xAt(index + 33) * factor * 1.3 - factor * 10 - y: yAt(index + 33) * factor * 1.05 + width * 0.45 - MouseArea { - anchors.fill: parent - hoverEnabled: !NOO.isAndroid() - onEntered: hiId = index + 33 - onExited: hiId = -1 - onClicked: { - if (!opening && !closing) - opening = true - currentIndex = index + 33 + Item { + height: parent.height + width: factor * 230 + + Repeater { + model: 38 + + Image { + source: NOO.pix("bando-button") + sourceSize.width: Math.round(parent.height / 6.5) + x: xAt(index + 33) * factor * 1.3 - factor * 10 + y: yAt(index + 33) * factor * 1.05 + width * 0.45 + + MouseArea { + anchors.fill: parent + hoverEnabled: !NOO.isAndroid() + onEntered: hiId = index + 33 + onExited: hiId = -1 + onClicked: { + if (!opening && !closing) + opening = true; + + currentIndex = index + 33; + } + } + + } + } - } + } - } + } - } + Rectangle { + id: hi + + color: GLOB.fingerColor + width: factor * 14.5 + height: width + radius: width / 2 + x: mainRow.x + (hiId > -1 ? (hiId > 32 ? rightX - factor * 10 : 0) + xAt(hiId) * factor * (hiId > 32 ? 1.3 : 1.1) : 0) + y: hiId > -1 ? yAt(hiId) * factor * (hiId > 32 ? 1.05 : 1.2) + width * ((hiId > 32 ? 0.48 : 0.28)) : 0 + visible: hiId > -1 + z: 20 + } - Rectangle { - id: hi - color: GLOB.fingerColor - width: factor * 14.5; height: width - radius: width / 2 - x: mainRow.x + (hiId > -1 ? (hiId > 32 ? rightX - factor * 10 : 0) + xAt(hiId) * factor * (hiId > 32 ? 1.3 : 1.1) : 0) - y: hiId > -1 ? yAt(hiId) * factor * (hiId > 32 ? 1.05 : 1.2) + width * ((hiId > 32 ? 0.48 : 0.28)) : 0 - visible: hiId > -1 - z: 20 - } + OutScaleTip { + show: !active && outOfScale + } - Component.onCompleted: { - if (NOO.isAndroid() && NOO.fingerPixels() * 4 > height) - bandoZoom = Qt.createComponent("qrc:/instruments/InstrumentZoom.qml").createObject(instrItem) - } + Behavior on scale { + enabled: GLOB.useAnimations - OutScaleTip { show: !active && outOfScale } + NumberAnimation { + duration: 150 + onRunningChanged: { + if (bandoZoom && !running && scale > 1) + instrFlick.contentX = bandoZoom.flickX; + } + } - onWantNoteName: { - if (!extraName) { - extraName = Qt.createComponent("qrc:/instruments/ExtraName.qml").createObject(instrItem) - extraName.fSize = Qt.binding(function() { return factor * 25 }) } - if (origin) { - extraName.text = name - extraName.x = Qt.binding(function() { return origin ? origin.x + (origin.width - extraName.width) / 2 : 0 }) - extraName.y = Qt.binding(function() { - return origin ? origin.y - (origin.y > instrItem.height / 2.5 ? 60 : 10) * factor : 0 - }) - } else - extraName.text = "" - } -} +} diff --git a/src/qml/instruments/ExtraName.qml b/src/qml/instruments/ExtraName.qml index 4761a392bd0fbdd81aa669be476b03e111fb2b51..dfdc38e9f5e95a11c1c39f7d0bd4f7f60e5e7857 100644 --- a/src/qml/instruments/ExtraName.qml +++ b/src/qml/instruments/ExtraName.qml @@ -2,28 +2,36 @@ * 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 Qt5Compat.GraphicalEffects - import Nootka 1.0 +import Qt5Compat.GraphicalEffects +import QtQuick 2.12 DropShadow { - z: 30 - property alias text: eText.text - property alias fSize: eText.font.pixelSize - - width: eText.width; height: eText.height - horizontalOffset: fSize / 25; verticalOffset: fSize / 25 - color: activPal.shadow - radius: NOO.factor() / 3 - source: eText - visible: text !== "" - Text { - id: eText - font { family: "Scorek"; pixelSize: NOO.factor() * 5 } - visible: false - style: Text.Outline; styleColor: activPal.shadow - } -} + property alias text: eText.text + property alias fSize: eText.font.pixelSize + z: 30 + width: eText.width + height: eText.height + horizontalOffset: fSize / 25 + verticalOffset: fSize / 25 + color: activPal.shadow + radius: NOO.factor() / 3 + source: eText + visible: text !== "" + Text { + id: eText + + visible: false + style: Text.Outline + styleColor: activPal.shadow + + font { + family: "Scorek" + pixelSize: NOO.factor() * 5 + } + + } + +} diff --git a/src/qml/instruments/Guitar.qml b/src/qml/instruments/Guitar.qml index f95305b85285da8d91bdf279623930487d23f43a..c51e9ea418e69b763acf2c8734baa01b72d8a6a1 100644 --- a/src/qml/instruments/Guitar.qml +++ b/src/qml/instruments/Guitar.qml @@ -2,139 +2,169 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 +import Nootka 1.0 import Qt5Compat.GraphicalEffects +import QtQuick 2.12 -import Nootka 1.0 +TguitarBg { + id: instrItem + // private + property var bodyPix: ["", "-electro", "-bass"] + property var correctAnim: null + property var guitarZoom: null -TguitarBg { - id: instrItem - - // private - property var bodyPix: ["", "-electro", "-bass"] - property var correctAnim: null - property var guitarZoom: null - - width: Math.max(nootkaWindow.width, GLOB.instrument.getItemHeight(nootkaWindow.shortEdge) * 5.4) - height: GLOB.instrument.getItemHeight(nootkaWindow.shortEdge) - - transformOrigin: Item.TopLeft - Behavior on scale { - enabled: GLOB.useAnimations - NumberAnimation { - duration: 150 - onRunningChanged: { - if (guitarZoom && !running && scale > 1) - instrFlick.contentX = guitarZoom.flickX - } - } - } - - onCorrectInstrument: { - if (!correctAnim) - correctAnim = Qt.createComponent("qrc:/exam/CorrectInstrAnim.qml").createObject(instrItem) - correctAnim.doCross = wrongItem === null - correctAnim.start() - } - - Item { - parent: nootkaWindow.contentItem - width: instrFlick.width; height: instrFlick.height; y: instrFlick.y - x: -instrFlick.contentX + width: Math.max(nootkaWindow.width, GLOB.instrument.getItemHeight(nootkaWindow.shortEdge) * 5.4) + height: GLOB.instrument.getItemHeight(nootkaWindow.shortEdge) transformOrigin: Item.TopLeft - scale: instrItem.scale - Image { // body - cache: false - source: GLOB.instrument.isGuitar && !GLOB.instrument.ukulele ? NOO.pix("body" + bodyPix[GLOB.instrument.typeINT - 1]) : "" - height: parent.height * (GLOB.instrument.classicGuitar ? 4 : 3.1) - width: height * (sourceSize.width / sourceSize.height) - x: GLOB.instrument.classicGuitar ? xiiFret : parent.width * 0.65 - y: parent.height - height * (GLOB.instrument.classicGuitar ? 0.95 : 0.97) + onCorrectInstrument: { + if (!correctAnim) + correctAnim = Qt.createComponent("qrc:/exam/CorrectInstrAnim.qml").createObject(instrItem); + + correctAnim.doCross = wrongItem === null; + correctAnim.start(); + } + Component.onCompleted: { + if (NOO.isAndroid() && NOO.fingerPixels() * 4 > height) + guitarZoom = Qt.createComponent("qrc:/instruments/InstrumentZoom.qml").createObject(instrItem); + } - Image { // rosette/pickup - cache: false - source: GLOB.instrument.isGuitar ? NOO.pix(GLOB.instrument.classicGuitar ? "rosette" : "pickup") : "" - height: parent.height * (GLOB.instrument.classicGuitar ? 1.55 : 1.3) - width: height * (sourceSize.width / sourceSize.height) - x: GLOB.instrument.classicGuitar ? fbRect.width - height * 0.25 : parent.width * 0.87 - y: parent.height - height * (GLOB.instrument.classicGuitar ? 0.95 : 0.88) + onWantNoteName: { + if (!extraName) { + extraName = Qt.createComponent("qrc:/instruments/ExtraName.qml").createObject(instrItem); + extraName.fSize = Qt.binding(function() { + return instrItem.height * 0.25; + }); + } + if (origin) { + extraName.text = name; + extraName.x = Qt.binding(function() { + return origin.x + (origin.width - extraName.width) / 2; + }); + extraName.y = Qt.binding(function() { + return origin.y - extraName.height * 0.4 + (origin.y > height / 2 ? -stringsGap : origin.height + stringsGap); + }); + } else { + extraName.text = ""; + } } - } - - Rectangle { - id: finger - color: GLOB.fingerColor - width: fretWidth / 1.6 - height: width * 0.65 - radius: width * 0.5 - x: fingerPos.x - y: fingerPos.y - visible: false - } - - DropShadow { - id: fingerShadow - z: 5 - anchors.fill: finger - horizontalOffset: finger.height / 6 - verticalOffset: finger.height / 6 - color: "black" - radius: NOO.factor() / 3 - source: finger - visible: fingerPos.x > 0 && active - scale: !pressed && active && fingerPos.x > 0 ? 1 : 0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - } - - Rectangle { // string highlight - z: 5 - color: finger.color - width: parent.width - stringsGap - 2 - height: string < 6 ? strWidth(string) * 1.5 : 0 - x: 1 - y: string < 6 ? fbRect.y + stringsGap / 2 + string * stringsGap - height / 3 : 0 - visible: !pressed && active && string < 6 && fingerPos.x == 0 - } - - Component.onCompleted: { - if (NOO.isAndroid() && NOO.fingerPixels() * 4 > height) - guitarZoom = Qt.createComponent("qrc:/instruments/InstrumentZoom.qml").createObject(instrItem) - } - - Connections { - target: instrFlick - enabled: !NOO.isAndroid() - onMovementEnded: instrument.pressedAt(0, 0) - } - - MouseArea { - property point startPos: Qt.point(0, 0) - enabled: NOO.isAndroid() && (NOO.fingerPixels() * 4 <= height || (guitarZoom && instrItem.scale > 1)) - width: parent.width; height: parent.height - onPressed: startPos = Qt.point(mouseX, mouseY) - onReleased: { - var dx = mouseX - startPos.x - var dy = mouseY - startPos.y - if (Math.sqrt(dx * dx + dy * dy) < fretWidth / 2) - pressedAt(mouse.x, mouse.y) + + Item { + parent: nootkaWindow.contentItem + width: instrFlick.width + height: instrFlick.height + y: instrFlick.y + x: -instrFlick.contentX + transformOrigin: Item.TopLeft + scale: instrItem.scale + + // body + Image { + cache: false + source: GLOB.instrument.isGuitar && !GLOB.instrument.ukulele ? NOO.pix("body" + bodyPix[GLOB.instrument.typeINT - 1]) : "" + height: parent.height * (GLOB.instrument.classicGuitar ? 4 : 3.1) + width: height * (sourceSize.width / sourceSize.height) + x: GLOB.instrument.classicGuitar ? xiiFret : parent.width * 0.65 + y: parent.height - height * (GLOB.instrument.classicGuitar ? 0.95 : 0.97) + } + + // rosette/pickup + Image { + cache: false + source: GLOB.instrument.isGuitar ? NOO.pix(GLOB.instrument.classicGuitar ? "rosette" : "pickup") : "" + height: parent.height * (GLOB.instrument.classicGuitar ? 1.55 : 1.3) + width: height * (sourceSize.width / sourceSize.height) + x: GLOB.instrument.classicGuitar ? fbRect.width - height * 0.25 : parent.width * 0.87 + y: parent.height - height * (GLOB.instrument.classicGuitar ? 0.95 : 0.88) + } + } - } - OutScaleTip { show: !active && outOfScale } + Rectangle { + id: finger - onWantNoteName: { - if (!extraName) { - extraName = Qt.createComponent("qrc:/instruments/ExtraName.qml").createObject(instrItem) - extraName.fSize = Qt.binding(function() { return instrItem.height * 0.25 }) + color: GLOB.fingerColor + width: fretWidth / 1.6 + height: width * 0.65 + radius: width * 0.5 + x: fingerPos.x + y: fingerPos.y + visible: false } - if (origin) { - extraName.text = name - extraName.x = Qt.binding(function() { return origin.x + (origin.width - extraName.width) / 2 }) - extraName.y = Qt.binding(function() { - return origin.y - extraName.height * 0.4 + (origin.y > height / 2 ? -stringsGap : origin.height + stringsGap) - }) - } else - extraName.text = "" - } + + DropShadow { + id: fingerShadow + + z: 5 + anchors.fill: finger + horizontalOffset: finger.height / 6 + verticalOffset: finger.height / 6 + color: "black" + radius: NOO.factor() / 3 + source: finger + visible: fingerPos.x > 0 && active + scale: !pressed && active && fingerPos.x > 0 ? 1 : 0 + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + } + + // string highlight + Rectangle { + z: 5 + color: finger.color + width: parent.width - stringsGap - 2 + height: string < 6 ? strWidth(string) * 1.5 : 0 + x: 1 + y: string < 6 ? fbRect.y + stringsGap / 2 + string * stringsGap - height / 3 : 0 + visible: !pressed && active && string < 6 && fingerPos.x == 0 + } + + Connections { + target: instrFlick + enabled: !NOO.isAndroid() + onMovementEnded: instrument.pressedAt(0, 0) + } + + MouseArea { + property point startPos: Qt.point(0, 0) + + enabled: NOO.isAndroid() && (NOO.fingerPixels() * 4 <= height || (guitarZoom && instrItem.scale > 1)) + width: parent.width + height: parent.height + onPressed: startPos = Qt.point(mouseX, mouseY) + onReleased: { + var dx = mouseX - startPos.x; + var dy = mouseY - startPos.y; + if (Math.sqrt(dx * dx + dy * dy) < fretWidth / 2) + pressedAt(mouse.x, mouse.y); + + } + } + + OutScaleTip { + show: !active && outOfScale + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + onRunningChanged: { + if (guitarZoom && !running && scale > 1) + instrFlick.contentX = guitarZoom.flickX; + + } + } + + } + } diff --git a/src/qml/instruments/Instrument.qml b/src/qml/instruments/Instrument.qml index ab1349523989e8f89eace1a698a2f06f362cf695..0f529fbdff59a484b2d10e21fc9ee554ad7b2dba 100644 --- a/src/qml/instruments/Instrument.qml +++ b/src/qml/instruments/Instrument.qml @@ -2,65 +2,63 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 +import QtQuick 2.12 import "score" - Flickable { - id: instrFlick - - property var instrument: null - property var score: null - - boundsBehavior: Flickable.StopAtBounds - height: sizable.height - width: nootkaWindow.width * (GLOB.instrument.isSax ? 0.15 : 1) - y: GLOB.instrument.isSax ? 0 : nootkaWindow.contentItem.height - height - x: GLOB.instrument.isSax ? parent.width - width : 0 - - z: instrument && instrument.scale > 1.0 ? 7 : (GLOB.instrument.isSax ? 6 : 1) + id: instrFlick + + property var instrument: null + property var score: null + property real hiFactor: GLOB.instrument.getItemHeight(100) / 100 + + function setInstrument() { + if (instrument) { + score.parent.scale = 1; + instrument.destroy(); + } + if (GLOB.instrument.type) + instrument = Qt.createComponent("qrc:/instruments/" + GLOB.instrument.qmlFile + ".qml").createObject(sizable); + else + instrument = null; + if (GLOB.instrument.piano) + instrument.setAmbitus(score.scoreObj.lowestNote(), score.scoreObj.highestNote()); + + NOO.instrument = instrument; + if (instrument && !GLOB.instrument.isSax) + score.parent.scale = Qt.binding(function() { + return (1 - hiFactor * instrument.scale) / (1 - hiFactor); + }); - contentWidth: sizable.width - contentHeight: sizable.height - - Item { - id: sizable - width: instrument ? instrument.width * instrument.scale : 0 - height: instrument ? instrument.height * instrument.scale : 0 - } - - Component.onCompleted: setInstrument() - - Connections { - target: GLOB - onInstrumentChanged: setInstrument() - } - - property real hiFactor: GLOB.instrument.getItemHeight(100) / 100.0 + } - function setInstrument() { - if (instrument) { - score.parent.scale = 1.0 - instrument.destroy() + boundsBehavior: Flickable.StopAtBounds + height: sizable.height + width: nootkaWindow.width * (GLOB.instrument.isSax ? 0.15 : 1) + y: GLOB.instrument.isSax ? 0 : nootkaWindow.contentItem.height - height + x: GLOB.instrument.isSax ? parent.width - width : 0 + z: instrument && instrument.scale > 1 ? 7 : (GLOB.instrument.isSax ? 6 : 1) + contentWidth: sizable.width + contentHeight: sizable.height + Component.onCompleted: setInstrument() + + Item { + id: sizable + + width: instrument ? instrument.width * instrument.scale : 0 + height: instrument ? instrument.height * instrument.scale : 0 } - if (GLOB.instrument.type) - instrument = Qt.createComponent("qrc:/instruments/" + GLOB.instrument.qmlFile + ".qml").createObject(sizable) - else - instrument = null + Connections { + target: GLOB + onInstrumentChanged: setInstrument() + } - if (GLOB.instrument.piano) - instrument.setAmbitus(score.scoreObj.lowestNote(), score.scoreObj.highestNote()) - NOO.instrument = instrument - if (instrument && !GLOB.instrument.isSax) - score.parent.scale = Qt.binding(function() { return (1.0 - hiFactor * instrument.scale) / (1 - hiFactor) }) - } + Connections { + target: score + enabled: GLOB.instrument.piano + onClefChanged: instrument.setAmbitus(score.scoreObj.lowestNote(), score.scoreObj.highestNote()) + } - Connections { - target: score - enabled: GLOB.instrument.piano - onClefChanged: instrument.setAmbitus(score.scoreObj.lowestNote(), score.scoreObj.highestNote()) - } } diff --git a/src/qml/instruments/InstrumentZoom.qml b/src/qml/instruments/InstrumentZoom.qml index 25a5ea943cf5a731a66f02e3bef6c1690f60a6e7..990873a17f2996a5a4a7207c500e65e851c8af31 100644 --- a/src/qml/instruments/InstrumentZoom.qml +++ b/src/qml/instruments/InstrumentZoom.qml @@ -2,58 +2,64 @@ * 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 Nootka 1.0 import "../" +import Nootka 1.0 +import QtQuick 2.12 MouseArea { - property real flickX: 0 - - enabled: instrItem.enabled && NOO.fingerPixels() * 4 > height && instrItem.scale === 1.0 - - width: instrItem.width; height: instrItem.height - z: 99 - - onClicked: { - var sc = (NOO.fingerPixels() * 4) / height - instrItem.scale = sc - flickX = (mouse.x / width) * (instrItem.width * sc - width) - } - - onEnabledChanged: { - if (!instrItem.enabled) - instrItem.scale = 1 - } - - property var scoreWrap: score.parent - Rectangle { // covers left side of zoomed-in score - parent: nootkaWindow.contentItem - width: (scoreWrap.width - scoreWrap.width * scoreWrap.scale) / 2 - height: scoreWrap.height * scoreWrap.scale - y: scoreWrap.y - color: NOO.alpha(activPal.base, 230) - z: 5 - } - Rectangle { // covers right side of zoomed-in score - parent: nootkaWindow.contentItem - width: (scoreWrap.width - scoreWrap.width * scoreWrap.scale) / 2 - height: scoreWrap.height * scoreWrap.scale - x: parent.width - width - y: scoreWrap.y - color: NOO.alpha(activPal.base, 230) - z: 5 - } - - Item { // overlay - visible: instrItem.scale > 1 - enabled: instrItem.enabled - parent: nootkaWindow.contentItem // NOTE valid only for Android - width: parent.width; height: parent.height - instrItem.height * instrItem.scale - z: 98 - MouseArea { - anchors.fill: parent - onClicked: instrItem.scale = 1 + property real flickX: 0 + property var scoreWrap: score.parent + + enabled: instrItem.enabled && NOO.fingerPixels() * 4 > height && instrItem.scale === 1 + width: instrItem.width + height: instrItem.height + z: 99 + onClicked: { + var sc = (NOO.fingerPixels() * 4) / height; + instrItem.scale = sc; + flickX = (mouse.x / width) * (instrItem.width * sc - width); + } + onEnabledChanged: { + if (!instrItem.enabled) + instrItem.scale = 1; + } - } + + // covers left side of zoomed-in score + Rectangle { + parent: nootkaWindow.contentItem + width: (scoreWrap.width - scoreWrap.width * scoreWrap.scale) / 2 + height: scoreWrap.height * scoreWrap.scale + y: scoreWrap.y + color: NOO.alpha(activPal.base, 230) + z: 5 + } + + // covers right side of zoomed-in score + Rectangle { + parent: nootkaWindow.contentItem + width: (scoreWrap.width - scoreWrap.width * scoreWrap.scale) / 2 + height: scoreWrap.height * scoreWrap.scale + x: parent.width - width + y: scoreWrap.y + color: NOO.alpha(activPal.base, 230) + z: 5 + } + + // overlay + Item { + visible: instrItem.scale > 1 + enabled: instrItem.enabled + parent: nootkaWindow.contentItem // NOTE valid only for Android + width: parent.width + height: parent.height - instrItem.height * instrItem.scale + z: 98 + + MouseArea { + anchors.fill: parent + onClicked: instrItem.scale = 1 + } + + } + } diff --git a/src/qml/instruments/OutScaleTip.qml b/src/qml/instruments/OutScaleTip.qml index 66b9ffa7c9a63579253f175592d99929315471e0..832d1d5d0887321f93d7d4248e003f06c0d870a6 100644 --- a/src/qml/instruments/OutScaleTip.qml +++ b/src/qml/instruments/OutScaleTip.qml @@ -2,33 +2,44 @@ * 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 Nootka 1.0 -import "../" +GlowRect { + property bool show: false + scale: show ? 1 : 0 + width: parent.width / 4 + height: NOO.factor() * (2 + txt.lineCount * 1.5) + anchors.centerIn: parent + z: 100 + color: Qt.tint("red", NOO.alpha(activPal.base, 70)) + shadowRadius: NOO.factor() -GlowRect { - property bool show: false + Text { + id: txt - scale: show ? 1 : 0 - width: parent.width / 4; height: NOO.factor() * (2 + txt.lineCount * 1.5) - anchors.centerIn: parent - z: 100 - color: Qt.tint("red", NOO.alpha(activPal.base, 70)) - shadowRadius: NOO.factor() + anchors.centerIn: parent + width: parent.width * 0.9 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: qsTr("Out of instrument scale!") + font.pixelSize: NOO.factor() * 1.5 + wrapMode: Text.WordWrap + fontSizeMode: Text.Fit + minimumPixelSize: NOO.factor() / 2 + minimumPointSize: minimumPixelSize + elide: Text.ElideRight + } - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } - Text { - id: txt - anchors.centerIn: parent - width: parent.width * 0.9 - horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter - text: qsTr("Out of instrument scale!") - font.pixelSize: NOO.factor() * 1.5 - wrapMode: Text.WordWrap - fontSizeMode: Text.Fit; minimumPixelSize: NOO.factor() / 2; minimumPointSize: minimumPixelSize - elide: Text.ElideRight - } } diff --git a/src/qml/instruments/Piano.qml b/src/qml/instruments/Piano.qml index f95c5cd4d010883c8633795b39a712c013be4aa8..b8e6cc70a2bc69eb01ac7e8f3eb55a239e03d095 100644 --- a/src/qml/instruments/Piano.qml +++ b/src/qml/instruments/Piano.qml @@ -2,134 +2,177 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 -import Nootka 1.0 +TpianoBg { + id: instrItem + property alias keysX: keysRow.x + property alias keysWidth: keysRow.width + // private + property var activeKey: null + property var correctAnim: null + property var pianoZoom: null -TpianoBg { - id: instrItem + function getKey(keyNr) { + return whiteRep.itemAt(keyNr); + } - property alias keysX: keysRow.x - property alias keysWidth: keysRow.width + width: Math.max(nootkaWindow.width, GLOB.instrument.getItemHeight(nootkaWindow.shortEdge) * 6.7) + height: GLOB.instrument.getItemHeight(nootkaWindow.shortEdge) + onWantKeyToSelect: selectKey(k > -1 ? (isWhite ? whiteRep.itemAt(k) : whiteRep.itemAt(k).black) : null) + transformOrigin: Item.TopLeft + onCorrectInstrument: { + if (!correctAnim) + correctAnim = Qt.createComponent("qrc:/exam/CorrectInstrAnim.qml").createObject(instrItem); - width: Math.max(nootkaWindow.width, GLOB.instrument.getItemHeight(nootkaWindow.shortEdge) * 6.7) - height: GLOB.instrument.getItemHeight(nootkaWindow.shortEdge) + correctAnim.doCross = !wrongItem.parent; + correctAnim.start(); + } + Component.onCompleted: { + if (NOO.isAndroid() && NOO.fingerPixels() * 4 > height) + pianoZoom = Qt.createComponent("qrc:/instruments/InstrumentZoom.qml").createObject(instrItem); - onWantKeyToSelect: selectKey(k > -1 ? (isWhite ? whiteRep.itemAt(k) : whiteRep.itemAt(k).black) : null) + } + onWantNoteName: { + if (!extraName) { + extraName = Qt.createComponent("qrc:/instruments/ExtraName.qml").createObject(instrItem); + extraName.fSize = Qt.binding(function() { + return keyWidth * 2; + }); + } + if (origin) { + extraName.text = name; + extraName.x = Qt.binding(function() { + return keysRow.x + (origin ? origin.nr * keyWidth + (origin.width - extraName.width) / 2 : 0); + }); + extraName.y = Qt.binding(function() { + return instrItem.height / 2 - extraName.height * (origin && origin.black ? 0.52 : 0.3); + }); + } else { + extraName.text = ""; + } + } - transformOrigin: Item.TopLeft - Behavior on scale { - enabled: GLOB.useAnimations - NumberAnimation { - duration: 150 - onRunningChanged: { - if (pianoZoom && !running && scale > 1) - instrFlick.contentX = pianoZoom.flickX - } + // piano background + Image { + parent: nootkaWindow.contentItem + cache: false + source: NOO.pix("pianoBg") + width: instrItem.width + height: width * (sourceSize.height / sourceSize.width) + x: -instrFlick.contentX + y: parent.height - instrItem.height * instrItem.scale - height + transformOrigin: Item.BottomLeft + scale: instrItem.scale } - } - - function getKey(keyNr) { return whiteRep.itemAt(keyNr) } - -// private - property var activeKey: null - property var correctAnim: null - property var pianoZoom: null - - onCorrectInstrument: { - if (!correctAnim) - correctAnim = Qt.createComponent("qrc:/exam/CorrectInstrAnim.qml").createObject(instrItem) - correctAnim.doCross = !wrongItem.parent - correctAnim.start() - } - - Image { // piano background - parent: nootkaWindow.contentItem - cache: false - source: NOO.pix("pianoBg") - width: instrItem.width; height: width * (sourceSize.height / sourceSize.width) - x: -instrFlick.contentX - y: parent.height - instrItem.height * instrItem.scale - height - transformOrigin: Item.BottomLeft - scale: instrItem.scale - } - - Rectangle { // black background - width: parent.width; height: parent.height - color: "black" - - Row { // keys - id: keysRow - anchors.horizontalCenter: parent.horizontalCenter - Repeater { - id: whiteRep - model: keysNumber - PianoKeyWhite { - nr: index - onEntered: activeKey = key - onClicked: selectedKey = key + + // black background + Rectangle { + width: parent.width + height: parent.height + color: "black" + + // keys + Row { + id: keysRow + + anchors.horizontalCenter: parent.horizontalCenter + + Repeater { + id: whiteRep + + model: keysNumber + + PianoKeyWhite { + nr: index + onEntered: activeKey = key + onClicked: selectedKey = key + } + + } + } - } + } - } - - keyHighlight: Rectangle { // piano key highlight - parent: selectedKey - anchors.fill: parent ? parent : undefined - color: GLOB.selectedColor - border { width: Math.round(keyWidth / 16); color: "black" } - radius: width / 5 - z: 2 - } - - Rectangle { // piano key cursor - anchors.fill: parent ? parent : undefined - parent: activeKey - z: 2 - color: GLOB.fingerColor - border { width: Math.round(keyWidth / 16); color: "black" } - radius: width / 5 - visible: active - } - - Rectangle { - id: octaveCover - width: parent.width; height: NOO.factor() * (NOO.isAndroid() ? 1 : 1.5) - color: "black" - Repeater { - model: Math.floor(keysNumber / 7) - Rectangle { - x: keysRow.x + index * width - width: keyWidth * 7; height: parent.height - color: index % 2 ? "#303030" : "black" - Text { - anchors.centerIn: parent - text: octaveName(firstOctave + index) + (GLOB.scientificOctaves ? " [%1]".arg(firstOctave + index + 3) : "") - font { pixelSize: parent.height * 0.8 } - color: "white" + + // piano key cursor + Rectangle { + anchors.fill: parent ? parent : undefined + parent: activeKey + z: 2 + color: GLOB.fingerColor + radius: width / 5 + visible: active + + border { + width: Math.round(keyWidth / 16) + color: "black" } - } + } - } - Component.onCompleted: { - if (NOO.isAndroid() && NOO.fingerPixels() * 4 > height) - pianoZoom = Qt.createComponent("qrc:/instruments/InstrumentZoom.qml").createObject(instrItem) - } + Rectangle { + id: octaveCover + + width: parent.width + height: NOO.factor() * (NOO.isAndroid() ? 1 : 1.5) + color: "black" + + Repeater { + model: Math.floor(keysNumber / 7) + + Rectangle { + x: keysRow.x + index * width + width: keyWidth * 7 + height: parent.height + color: index % 2 ? "#303030" : "black" + + Text { + anchors.centerIn: parent + text: octaveName(firstOctave + index) + (GLOB.scientificOctaves ? " [%1]".arg(firstOctave + index + 3) : "") + color: "white" + + font { + pixelSize: parent.height * 0.8 + } + + } + + } + + } + + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + onRunningChanged: { + if (pianoZoom && !running && scale > 1) + instrFlick.contentX = pianoZoom.flickX; + + } + } - onWantNoteName: { - if (!extraName) { - extraName = Qt.createComponent("qrc:/instruments/ExtraName.qml").createObject(instrItem) - extraName.fSize = Qt.binding(function() { return keyWidth * 2 }) } - if (origin) { - extraName.text = name - extraName.x = Qt.binding(function() { - return keysRow.x + (origin ? origin.nr * keyWidth + (origin.width - extraName.width) / 2 : 0) - }) - extraName.y = Qt.binding(function() { return instrItem.height / 2 - extraName.height * (origin && origin.black ? 0.52 : 0.3) }) - } else - extraName.text = "" - } + + // piano key highlight + keyHighlight: Rectangle { + parent: selectedKey + anchors.fill: parent ? parent : undefined + color: GLOB.selectedColor + radius: width / 5 + z: 2 + + border { + width: Math.round(keyWidth / 16) + color: "black" + } + + } + } diff --git a/src/qml/instruments/PianoKeyBlack.qml b/src/qml/instruments/PianoKeyBlack.qml index 7f803ab6d47393a6fb230b2820449c4f91f38a46..05d0c8344e26ab8aa34a1913ef49a75b892dbea0 100644 --- a/src/qml/instruments/PianoKeyBlack.qml +++ b/src/qml/instruments/PianoKeyBlack.qml @@ -2,26 +2,29 @@ * Copyright (C) 2020-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 +import QtQuick 2.12 Image { - id: blackKey + id: blackKey + + property int nr: -1 + + source: NOO.pix("pianokey") + width: Math.round(parent.width * 0.8) + height: parent.height / 2 + x: -parent.width * 0.4 + y: NOO.factor() * (NOO.isAndroid() ? 1 : 1.5) + z: 3 - property int nr: -1 + MouseArea { + id: ma - source: NOO.pix("pianokey") - width: Math.round(parent.width * 0.8); height: parent.height / 2 - x: -parent.width * 0.4; y: NOO.factor() * (NOO.isAndroid() ? 1 : 1.5) - z: 3 + anchors.fill: parent + hoverEnabled: true + onEntered: whiteKey.entered(blackKey) + onClicked: whiteKey.clicked(blackKey) + onExited: whiteKey.entered(null) + } - MouseArea { - id: ma - anchors.fill: parent - hoverEnabled: true - onEntered: whiteKey.entered(blackKey) - onClicked: whiteKey.clicked(blackKey) - onExited: whiteKey.entered(null) - } } diff --git a/src/qml/instruments/PianoKeyWhite.qml b/src/qml/instruments/PianoKeyWhite.qml index 64b98a35040b889a04be99cb1ab9bb590d7016f3..11768b9b663447bb7cc023e44b88ae819408499c 100644 --- a/src/qml/instruments/PianoKeyWhite.qml +++ b/src/qml/instruments/PianoKeyWhite.qml @@ -4,40 +4,50 @@ import QtQuick 2.12 - Rectangle { - id: whiteKey - - property int nr: -1 - property Item black: null - - signal entered(var key) - signal clicked(var key) - - width: instrItem.keyWidth; height: instrItem.height; - radius: width / 5; color: "white" - border { width: Math.round(width / 16); color: "black" } - - MouseArea { - id: ma - property point startPos: Qt.point(0, 0) - anchors.fill: parent - hoverEnabled: true - onEntered: whiteKey.entered(whiteKey) - onPressed: startPos = Qt.point(mouseX, mouseY) - onReleased: { - var dx = mouseX - startPos.x - var dy = mouseY - startPos.y - if (Math.sqrt(dx * dx + dy * dy) < width * 2) - whiteKey.clicked(whiteKey) + id: whiteKey + + property int nr: -1 + property Item black: null + + signal entered(var key) + signal clicked(var key) + + width: instrItem.keyWidth + height: instrItem.height + radius: width / 5 + color: "white" + Component.onCompleted: { + if (index % 7 !== 0 && index % 7 !== 3) { + var bk = Qt.createComponent("qrc:/instruments/PianoKeyBlack.qml"); + black = bk.createObject(whiteKey, { + "nr": index + }); + } } - onExited: whiteKey.entered(null) - } - Component.onCompleted: { - if (index % 7 !== 0 && index % 7 !== 3) { - var bk = Qt.createComponent("qrc:/instruments/PianoKeyBlack.qml") - black = bk.createObject(whiteKey, { "nr": index }) + border { + width: Math.round(width / 16) + color: "black" } - } + + MouseArea { + id: ma + + property point startPos: Qt.point(0, 0) + + anchors.fill: parent + hoverEnabled: true + onEntered: whiteKey.entered(whiteKey) + onPressed: startPos = Qt.point(mouseX, mouseY) + onReleased: { + var dx = mouseX - startPos.x; + var dy = mouseY - startPos.y; + if (Math.sqrt(dx * dx + dy * dy) < width * 2) + whiteKey.clicked(whiteKey); + + } + onExited: whiteKey.entered(null) + } + } diff --git a/src/qml/instruments/Sax.qml b/src/qml/instruments/Sax.qml index 1ab906cbeff3fe243e75cc30ed596138da0b6efe..f112a14905418c6aa9d521d46a9ee42f716a7edc 100644 --- a/src/qml/instruments/Sax.qml +++ b/src/qml/instruments/Sax.qml @@ -2,114 +2,308 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - - TsaxBg { - id: instrItem - - // private - property real xAxis: height * 0.096 // line.x - property color checkedColor: activPal.text - property var activeFlap: null - - width: Math.max(nootkaWindow.width * 0.15, nootkaWindow.height * 0.21) - height: nootkaWindow.height - - Image { // body - parent: nootkaWindow.contentItem - cache: false - source: NOO.pix("saxAlto") - height: instrFlick.height * 0.9; width: height * (sourceSize.width/ sourceSize.height) - x: parent.width * 0.85 - instrFlick.contentX - width * 0.25 - } - - -// Rectangle { // debug usage only -// id: line -// width: 2; height: parent.height -// x: parent.height * 0.096 -// color: "blue" -// } - - // left fingers - SaxFlap { nr: 0; width: parent.height / 34; x: xAxis - width; y: parent.height * 0.1 } - SaxFlap { nr: 1; x: xAxis - width / 2; y: parent.height * 0.14 } - SaxFlap { nr: 2; width: parent.height / 34; x: xAxis; y: parent.height * 0.2 } - SaxFlap { nr: 3; x: xAxis - width / 2; y: parent.height * 0.25 } - SaxFlap { nr: 4; x: xAxis - width / 2; y: parent.height * 0.32 } - // left side flaps - SaxFlap { nr: 5; x: xAxis - width / 2; y: parent.height * 0.5 } - SaxFlap { nr: 6; x: xAxis - width / 2; y: parent.height * 0.56 } - SaxFlap { nr: 7; x: xAxis - width / 2; y: parent.height * 0.62 } - // left pinkie cluster - SaxFlap { nr: 8; x: xAxis + width * 1.5; y: parent.height * 0.17; width: parent.height / 34; height: width * 2; rotation: -10 } - SaxFlap { nr: 9; x: xAxis + width * 2.25; y: parent.height * 0.13; width: parent.height / 34; height: width * 2; rotation: -10 } - SaxFlap { nr: 10; x: xAxis + width * 3.25; y: parent.height * 0.17; width: parent.height / 34; height: width * 2; rotation: -10 } - // left thumb - SaxFlap { nr: 11; x: xAxis - width * 2; width: parent.height / 22; height: width * 0.8 ; y: parent.height * 0.22 } - - // right hand - SaxFlap { nr: 12; x: xAxis + width; y: parent.height * 0.4; width: parent.height / 18; height: width / 2 } - SaxFlap { nr: 13; x: xAxis + width * 1.2; y: parent.height * 0.43; width: parent.height / 26; height: width / 2 } - SaxFlap { nr: 14; x: xAxis + width * 2.2; y: parent.height * 0.43; width: parent.height / 26; height: width / 2 } - SaxFlap { nr: 15; x: xAxis + width; y: parent.height * 0.45; width: parent.height / 18; height: width / 2 } - // right hand side flaps - SaxFlap { nr: 16; x: xAxis - width * 2.5; y: parent.height * 0.4; width: parent.height / 34; height: width * 2; radius: 0 } - SaxFlap { nr: 17; x: xAxis - width * 2.5; y: parent.height * 0.46; width: parent.height / 34; height: width * 1.8; radius: 0 } - SaxFlap { nr: 18; x: xAxis - width * 2.5; y: parent.height * 0.515; width: parent.height / 34; height: width * 1.5; radius: 0 } - // ... - SaxFlap { nr: 19; x: xAxis - width * 2.5; y: parent.height * 0.6; width: parent.height / 34; height: width * 2; radius: 0; rotation: 10 } - SaxFlap { nr: 20; x: xAxis - width * 2.6; y: parent.height * 0.66; width: parent.height / 34; height: width * 2; radius: 0; rotation: 10 } - // right pinkie flaps - SaxFlap { nr: 21; x: xAxis - width * 1.5; y: parent.height * 0.75; width: parent.height / 18; height: width / 2; rotation: 30 } - SaxFlap { nr: 22; x: xAxis - width * 1.5; y: parent.height * 0.78; width: parent.height / 18; height: width / 2; rotation: 30 } - - OutScaleTip { show: !active && outOfScale; width: parent.width * 0.9 } - - //TextEdit { // for debug purposes - number representing fingers shape + // Rectangle { // debug usage only + // id: line + // width: 2; height: parent.height + // x: parent.height * 0.096 + // color: "blue" + // } + //TextEdit { // for debug purposes - number representing fingers shape //anchors.top: parent.top; anchors.horizontalCenter: parent.horizontalCenter //font.pixelSize: 30 //text: fingeringId - //} - - Rectangle { // sax flap cursor - parent: activeFlap - anchors.fill: parent ? parent : undefined - z: 2 - color: GLOB.fingerColor - radius: parent ? parent.radius : 0 - visible: active - scale: parent && parent.pressed ? 0.3 : 1 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 } } - } - - onWantNoteName: { - if (!extraName) { - extraName = Qt.createComponent("qrc:/instruments/ExtraName.qml").createObject(instrItem, - { "y": instrItem.height * 0.22 }) - extraName.fSize = Qt.binding(function() { return instrItem.height / 18 }) - extraName.x = Qt.binding(function() { return width - extraName.width - 2 * NOO.factor() }) - } - extraName.text = name - } - - onCorrectInstrument: { - var correctAnim = animComp.createObject(instrItem) - correctAnim.start() - } - - Component { - id: animComp - SequentialAnimation { - ColorAnimation { target: instrItem; property: "checkedColor"; to: activPal.base; duration: 400 } - ScriptAction { script: instrItem.applyCorrect() } - ColorAnimation { target: instrItem; property: "checkedColor"; to: activPal.text; duration: 400 } - ScriptAction { script: instrItem.finishCorrectAnim() } - onStopped: destroy() - } - } + //} + + id: instrItem + + // private + property real xAxis: height * 0.096 + // line.x + property color checkedColor: activPal.text + property var activeFlap: null + + width: Math.max(nootkaWindow.width * 0.15, nootkaWindow.height * 0.21) + height: nootkaWindow.height + onWantNoteName: { + if (!extraName) { + extraName = Qt.createComponent("qrc:/instruments/ExtraName.qml").createObject(instrItem, { + "y": instrItem.height * 0.22 + }); + extraName.fSize = Qt.binding(function() { + return instrItem.height / 18; + }); + extraName.x = Qt.binding(function() { + return width - extraName.width - 2 * NOO.factor(); + }); + } + extraName.text = name; + } + onCorrectInstrument: { + var correctAnim = animComp.createObject(instrItem); + correctAnim.start(); + } + + // body + Image { + parent: nootkaWindow.contentItem + cache: false + source: NOO.pix("saxAlto") + height: instrFlick.height * 0.9 + width: height * (sourceSize.width / sourceSize.height) + x: parent.width * 0.85 - instrFlick.contentX - width * 0.25 + } + + // left fingers + SaxFlap { + nr: 0 + width: parent.height / 34 + x: xAxis - width + y: parent.height * 0.1 + } + + SaxFlap { + nr: 1 + x: xAxis - width / 2 + y: parent.height * 0.14 + } + + SaxFlap { + nr: 2 + width: parent.height / 34 + x: xAxis + y: parent.height * 0.2 + } + + SaxFlap { + nr: 3 + x: xAxis - width / 2 + y: parent.height * 0.25 + } + + SaxFlap { + nr: 4 + x: xAxis - width / 2 + y: parent.height * 0.32 + } + // left side flaps + + SaxFlap { + nr: 5 + x: xAxis - width / 2 + y: parent.height * 0.5 + } + + SaxFlap { + nr: 6 + x: xAxis - width / 2 + y: parent.height * 0.56 + } + + SaxFlap { + nr: 7 + x: xAxis - width / 2 + y: parent.height * 0.62 + } + // left pinkie cluster + + SaxFlap { + nr: 8 + x: xAxis + width * 1.5 + y: parent.height * 0.17 + width: parent.height / 34 + height: width * 2 + rotation: -10 + } + + SaxFlap { + nr: 9 + x: xAxis + width * 2.25 + y: parent.height * 0.13 + width: parent.height / 34 + height: width * 2 + rotation: -10 + } + + SaxFlap { + nr: 10 + x: xAxis + width * 3.25 + y: parent.height * 0.17 + width: parent.height / 34 + height: width * 2 + rotation: -10 + } + // left thumb + + SaxFlap { + nr: 11 + x: xAxis - width * 2 + width: parent.height / 22 + height: width * 0.8 + y: parent.height * 0.22 + } + + // right hand + SaxFlap { + nr: 12 + x: xAxis + width + y: parent.height * 0.4 + width: parent.height / 18 + height: width / 2 + } + + SaxFlap { + nr: 13 + x: xAxis + width * 1.2 + y: parent.height * 0.43 + width: parent.height / 26 + height: width / 2 + } + + SaxFlap { + nr: 14 + x: xAxis + width * 2.2 + y: parent.height * 0.43 + width: parent.height / 26 + height: width / 2 + } + + SaxFlap { + nr: 15 + x: xAxis + width + y: parent.height * 0.45 + width: parent.height / 18 + height: width / 2 + } + // right hand side flaps + + SaxFlap { + nr: 16 + x: xAxis - width * 2.5 + y: parent.height * 0.4 + width: parent.height / 34 + height: width * 2 + radius: 0 + } + + SaxFlap { + nr: 17 + x: xAxis - width * 2.5 + y: parent.height * 0.46 + width: parent.height / 34 + height: width * 1.8 + radius: 0 + } + + SaxFlap { + nr: 18 + x: xAxis - width * 2.5 + y: parent.height * 0.515 + width: parent.height / 34 + height: width * 1.5 + radius: 0 + } + // ... + + SaxFlap { + nr: 19 + x: xAxis - width * 2.5 + y: parent.height * 0.6 + width: parent.height / 34 + height: width * 2 + radius: 0 + rotation: 10 + } + + SaxFlap { + nr: 20 + x: xAxis - width * 2.6 + y: parent.height * 0.66 + width: parent.height / 34 + height: width * 2 + radius: 0 + rotation: 10 + } + // right pinkie flaps + + SaxFlap { + nr: 21 + x: xAxis - width * 1.5 + y: parent.height * 0.75 + width: parent.height / 18 + height: width / 2 + rotation: 30 + } + + SaxFlap { + nr: 22 + x: xAxis - width * 1.5 + y: parent.height * 0.78 + width: parent.height / 18 + height: width / 2 + rotation: 30 + } + + OutScaleTip { + show: !active && outOfScale + width: parent.width * 0.9 + } + + // sax flap cursor + Rectangle { + parent: activeFlap + anchors.fill: parent ? parent : undefined + z: 2 + color: GLOB.fingerColor + radius: parent ? parent.radius : 0 + visible: active + scale: parent && parent.pressed ? 0.3 : 1 + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + } + + Component { + id: animComp + + SequentialAnimation { + onStopped: destroy() + + ColorAnimation { + target: instrItem + property: "checkedColor" + to: activPal.base + duration: 400 + } + + ScriptAction { + script: instrItem.applyCorrect() + } + + ColorAnimation { + target: instrItem + property: "checkedColor" + to: activPal.text + duration: 400 + } + + ScriptAction { + script: instrItem.finishCorrectAnim() + } + + } + + } + } diff --git a/src/qml/instruments/SaxFlap.qml b/src/qml/instruments/SaxFlap.qml index e3b9bd578fee59c2514fa6f30797c938fa1c4cbc..efebb3ac2cad1b953c41a3d446a04c0b9529b36f 100644 --- a/src/qml/instruments/SaxFlap.qml +++ b/src/qml/instruments/SaxFlap.qml @@ -4,28 +4,32 @@ import QtQuick 2.12 - Rectangle { - property int nr: -1 - property bool checked: fingeringId & Math.pow(2, nr) - property alias pressed: ma.pressed + property int nr: -1 + property bool checked: fingeringId & Math.pow(2, nr) + property alias pressed: ma.pressed + // private + property bool marked: checked && parent.markColor.a + + color: checked ? checkedColor : activPal.base + x: (parent.width - width) / 2 + width: parent.height / 20 + height: width + radius: width / 2 + + border { + width: (marked ? 4 : 2) + color: marked ? parent.markColor : activPal.text + } - // private - property bool marked: checked && parent.markColor.a + MouseArea { + id: ma - color: checked ? checkedColor : activPal.base - x: (parent.width - width) / 2 - width: parent.height / 20 - height: width - radius: width / 2 - border { width: (marked ? 4 : 2); color: marked ? parent.markColor : activPal.text } + anchors.fill: parent + hoverEnabled: true + onClicked: flapNumber = nr + onEntered: activeFlap = parent + onExited: activeFlap = null + } - MouseArea { - id: ma - anchors.fill: parent - hoverEnabled: true - onClicked: flapNumber = nr - onEntered: activeFlap = parent - onExited: activeFlap = null - } } diff --git a/src/qml/instruments/Ukulele.qml b/src/qml/instruments/Ukulele.qml index 5464d65b2c0d868e67bfe065c70c87befe6d2642..480d6ffa828a0b83f31e68d9c410fbc8a83adc86 100644 --- a/src/qml/instruments/Ukulele.qml +++ b/src/qml/instruments/Ukulele.qml @@ -2,143 +2,181 @@ * 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 Nootka 1.0 import QtGraphicalEffects 1.0 +import QtQuick 2.12 -import Nootka 1.0 +TguitarBg { + id: instrItem + // private + property var correctAnim: null + property var guitarZoom: null -TguitarBg { - id: instrItem - - // private - property var correctAnim: null - property var guitarZoom: null - - width: Math.max(nootkaWindow.width, GLOB.instrument.getItemHeight(nootkaWindow.height) * 5.4) - height: GLOB.instrument.getItemHeight(nootkaWindow.shortEdge) - - transformOrigin: Item.TopLeft - Behavior on scale { - enabled: GLOB.useAnimations - NumberAnimation { - duration: 150 - onRunningChanged: { - if (guitarZoom && !running && scale > 1) - instrFlick.contentX = guitarZoom.flickX - } - } - } - - onCorrectInstrument: { - if (!correctAnim) - correctAnim = Qt.createComponent("qrc:/exam/CorrectInstrAnim.qml").createObject(instrItem) - correctAnim.doCross = wrongItem === null - correctAnim.start() - } - - Item { - parent: nootkaWindow.contentItem - width: instrFlick.width; height: instrFlick.height; y: instrFlick.y - x: -instrFlick.contentX + width: Math.max(nootkaWindow.width, GLOB.instrument.getItemHeight(nootkaWindow.height) * 5.4) + height: GLOB.instrument.getItemHeight(nootkaWindow.shortEdge) transformOrigin: Item.TopLeft - scale: instrItem.scale - Image { // body - cache: false - source: NOO.pix("body-ukulele") - height: parent.height * 5 - width: height * (sourceSize.width / sourceSize.height) - x: xiiFret; y: parent.height - height * 0.67 + onCorrectInstrument: { + if (!correctAnim) + correctAnim = Qt.createComponent("qrc:/exam/CorrectInstrAnim.qml").createObject(instrItem); + + correctAnim.doCross = wrongItem === null; + correctAnim.start(); + } + Component.onCompleted: { + if (NOO.isAndroid() && NOO.fingerPixels() * 4 > height) + guitarZoom = Qt.createComponent("qrc:/instruments/InstrumentZoom.qml").createObject(instrItem); + + } + onWantNoteName: { + if (!extraName) { + extraName = Qt.createComponent("qrc:/instruments/ExtraName.qml").createObject(instrItem); + extraName.fSize = Qt.binding(function() { + return instrItem.height * 0.25; + }); + } + if (origin) { + extraName.text = name; + extraName.x = Qt.binding(function() { + return origin.x + (origin.width - extraName.width) / 2; + }); + extraName.y = Qt.binding(function() { + return origin.y - extraName.height * 0.4 + (origin.y > height / 2 ? -stringsGap : origin.height + stringsGap); + }); + } else { + extraName.text = ""; + } + } + + Item { + parent: nootkaWindow.contentItem + width: instrFlick.width + height: instrFlick.height + y: instrFlick.y + x: -instrFlick.contentX + transformOrigin: Item.TopLeft + scale: instrItem.scale + + // body + Image { + cache: false + source: NOO.pix("body-ukulele") + height: parent.height * 5 + width: height * (sourceSize.width / sourceSize.height) + x: xiiFret + y: parent.height - height * 0.67 + } + + // strings shadow over body + Repeater { + model: 4 + + Rectangle { + x: fbRect.x + fbRect.width + y: fbRect.y + stringsGap / 2 + index * stringsGap + 2.5 * height + width: parent.width - x - stringsGap * 0.8 + height: strWidth(index) + color: "#201c1c1c" + } + + } + + Image { + cache: false + source: NOO.pix("rosette-ukulele") + x: fbRect.width + height * 0.5 + y: parent.height - fbRect.height * parent.scale + width: fbRect.height + height: fbRect.height + } + + } + + Rectangle { + id: finger + + color: GLOB.fingerColor + width: fretWidth / 1.6 + height: width * 0.65 + radius: width * 0.5 + x: fingerPos.x + y: fingerPos.y + visible: false } - Repeater { // strings shadow over body - model: 4 - Rectangle { - x: fbRect.x + fbRect.width; y: fbRect.y + stringsGap / 2 + index * stringsGap + 2.5 * height - width: parent.width - x - stringsGap * 0.8; height: strWidth(index) - color: "#201c1c1c" - } + + DropShadow { + id: fingerShadow + + z: 5 + anchors.fill: finger + horizontalOffset: finger.height / 6 + verticalOffset: finger.height / 6 + color: "black" + radius: NOO.factor() / 3 + source: finger + visible: fingerPos.x > 0 && active + scale: !pressed && active && fingerPos.x > 0 ? 1 : 0 + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + } - Image { - cache: false - source: NOO.pix("rosette-ukulele") - x: fbRect.width + height * 0.5; y: parent.height - fbRect.height * parent.scale - width: fbRect.height; height: fbRect.height + + // string highlight + Rectangle { + z: 5 + color: finger.color + width: parent.width - stringsGap - 2 + height: string < 6 ? strWidth(string) * 1.75 : 0 + x: 1 + y: string < 6 ? fbRect.y + stringsGap / 2 + string * stringsGap - height / 2 : 0 + visible: !pressed && active && string < 6 && fingerPos.x == 0 } - } - - Rectangle { - id: finger - color: GLOB.fingerColor - width: fretWidth / 1.6 - height: width * 0.65 - radius: width * 0.5 - x: fingerPos.x - y: fingerPos.y - visible: false - } - - DropShadow { - id: fingerShadow - z: 5 - anchors.fill: finger - horizontalOffset: finger.height / 6 - verticalOffset: finger.height / 6 - color: "black" - radius: NOO.factor() / 3 - source: finger - visible: fingerPos.x > 0 && active - scale: !pressed && active && fingerPos.x > 0 ? 1 : 0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - } - - Rectangle { // string highlight - z: 5 - color: finger.color - width: parent.width - stringsGap - 2 - height: string < 6 ? strWidth(string) * 1.75 : 0 - x: 1 - y: string < 6 ? fbRect.y + stringsGap / 2 + string * stringsGap - height / 2 : 0 - visible: !pressed && active && string < 6 && fingerPos.x == 0 - } - - Component.onCompleted: { - if (NOO.isAndroid() && NOO.fingerPixels() * 4 > height) - guitarZoom = Qt.createComponent("qrc:/instruments/InstrumentZoom.qml").createObject(instrItem) - } - - Connections { - target: instrFlick - enabled: !NOO.isAndroid() - onMovementEnded: instrument.pressedAt(0, 0) - } - - MouseArea { - property point startPos: Qt.point(0, 0) - enabled: NOO.isAndroid() && (NOO.fingerPixels() * 4 <= height) || (guitarZoom && instrItem.scale > 1) - width: parent.width; height: parent.height - onPressed: startPos = Qt.point(mouseX, mouseY) - onReleased: { - var dx = mouseX - startPos.x - var dy = mouseY - startPos.y - if (Math.sqrt(dx * dx + dy * dy) < fretWidth / 2) - pressedAt(mouse.x, mouse.y) + + Connections { + target: instrFlick + enabled: !NOO.isAndroid() + onMovementEnded: instrument.pressedAt(0, 0) } - } - OutScaleTip { show: !active && outOfScale } + MouseArea { + property point startPos: Qt.point(0, 0) + + enabled: NOO.isAndroid() && (NOO.fingerPixels() * 4 <= height) || (guitarZoom && instrItem.scale > 1) + width: parent.width + height: parent.height + onPressed: startPos = Qt.point(mouseX, mouseY) + onReleased: { + var dx = mouseX - startPos.x; + var dy = mouseY - startPos.y; + if (Math.sqrt(dx * dx + dy * dy) < fretWidth / 2) + pressedAt(mouse.x, mouse.y); - onWantNoteName: { - if (!extraName) { - extraName = Qt.createComponent("qrc:/instruments/ExtraName.qml").createObject(instrItem) - extraName.fSize = Qt.binding(function() { return instrItem.height * 0.25 }) + } } - if (origin) { - extraName.text = name - extraName.x = Qt.binding(function() { return origin.x + (origin.width - extraName.width) / 2 }) - extraName.y = Qt.binding(function() { - return origin.y - extraName.height * 0.4 + (origin.y > height / 2 ? -stringsGap : origin.height + stringsGap) - }) - } else - extraName.text = "" - } + + OutScaleTip { + show: !active && outOfScale + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + onRunningChanged: { + if (guitarZoom && !running && scale > 1) + instrFlick.contentX = guitarZoom.flickX; + + } + } + + } + } diff --git a/src/qml/level/AccidsPage.qml b/src/qml/level/AccidsPage.qml index 286165f4c4d76d219248e1e7aec565d396824f57..c5528bfc847bfd5db8da2056a34842d66e0543ae 100644 --- a/src/qml/level/AccidsPage.qml +++ b/src/qml/level/AccidsPage.qml @@ -2,157 +2,213 @@ * 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 Nootka 1.0 -import "../" - Tflickable { - height: parent.height - contentHeight: accidsGrid.height + NOO.factor() * 2 - contentWidth: Math.max(width, NOO.factor() * 40) - - Grid { - columns: parent.width > NOO.factor() * 60 ? 2 : 1 - id: accidsGrid - width: parent.width - spacing: NOO.factor() / 4 - horizontalItemAlignment: Grid.AlignHCenter - topPadding: NOO.factor() - - Tframe { - width: accidsGrid.columns === 1 ? Math.max(parent.width * 0.9, dblAccidsChB.width) : parent.width * 0.4 - enabled: creator.howGetMelody !== 2 || !creator.isMelody - Column { - spacing: NOO.factor() / 2 - width: parent.width - Text { text: qsTr("accidentals"); color: activPal.text; anchors.horizontalCenter: parent.horizontalCenter } - Tile { - TcheckBox { - id: sharpsChB - enabled: !(useKeysChB.checked && (loKeyCombo.currentIndex > 7 || (rangeKeysChB.checked && hiKeyCombo.currentIndex > 7))) - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("# - sharps") - checked: creator.withSharps - onClicked: creator.withSharps = checked - } - description: qsTr("Sharps will be used in questions and answers. It has to be checked, if keys with sharps are used.") - } - Tile { - TcheckBox { - id: flatsChB - enabled: !(useKeysChB.checked && (loKeyCombo.currentIndex < 7 || (rangeKeysChB.checked && hiKeyCombo.currentIndex < 7))) - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("b - flats") - checked: creator.withFlats - onClicked: creator.withFlats = checked - } - description: qsTr("Flats will be used in questions and answers. It has to be checked, if keys with flats are used.") - } - Tile { - TcheckBox { - id: dblAccidsChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("x, bb - double accidentals") - checked: creator.withDblAccids - onClicked: creator.withDblAccids = checked - } - } - Tile { - TcheckBox { - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("force using appropriate accidental") - checked: creator.forceAccids - onClicked: creator.forceAccids = checked - } - description: qsTr("if checked, it is possible to select a note with given accidental only.") - } - } - } // accids frame - - Tframe { - id: keyFrame - width: accidsGrid.columns === 1 ? parent.width * 0.98 : parent.width * 0.59 - Column { - spacing: NOO.factor() / 2 + height: parent.height + contentHeight: accidsGrid.height + NOO.factor() * 2 + contentWidth: Math.max(width, NOO.factor() * 40) + + Grid { + id: accidsGrid + + columns: parent.width > NOO.factor() * 60 ? 2 : 1 width: parent.width - TcheckBox { - id: useKeysChB - text: NOO.TR("ScorePage", "use key signatures") - anchors.horizontalCenter: parent.horizontalCenter - checked: creator.useKeySign - onClicked: creator.useKeySign = checked - } - ButtonGroup { id: keysGr } - Tile { - enabled: useKeysChB.checked - TradioButton { - text: qsTr("single key") - ButtonGroup.group: keysGr - anchors.horizontalCenter: parent.horizontalCenter - checked: creator.isSingleKey - onClicked: creator.isSingleKey = checked - } - description: qsTr("Only one, selected key signature for whole exam.") - } - Tile { - enabled: useKeysChB.checked - TradioButton { - id: rangeKeysChB - text: qsTr("range of keys") - ButtonGroup.group: keysGr - anchors.horizontalCenter: parent.horizontalCenter - checked: !creator.isSingleKey - onClicked: creator.isSingleKey = !checked - } - description: qsTr("Random key signature from selected range.") - } - Tile { - enabled: useKeysChB.checked - Row { - spacing: NOO.factor() / 2 - anchors.horizontalCenter: parent.horizontalCenter - TcomboBox { - id: loKeyCombo - model: NOO.keyComboModel() - width: keyFrame.width * 0.4 - currentIndex: creator.loKey + 7 - onActivated: creator.loKey = currentIndex - 7 - } - Rectangle { - color: enabled ? activPal.text : disdPal.text; width: NOO.factor(); height: NOO.factor() / 5 - anchors.verticalCenter: parent.verticalCenter - } - TcomboBox { - enabled: rangeKeysChB.checked - id: hiKeyCombo - model: NOO.keyComboModel() - width: keyFrame.width * 0.4 - currentIndex: creator.hiKey + 7 - onActivated: creator.hiKey = currentIndex - 7 + spacing: NOO.factor() / 4 + horizontalItemAlignment: Grid.AlignHCenter + topPadding: NOO.factor() + + Tframe { + width: accidsGrid.columns === 1 ? Math.max(parent.width * 0.9, dblAccidsChB.width) : parent.width * 0.4 + enabled: creator.howGetMelody !== 2 || !creator.isMelody + + Column { + spacing: NOO.factor() / 2 + width: parent.width + + Text { + text: qsTr("accidentals") + color: activPal.text + anchors.horizontalCenter: parent.horizontalCenter + } + + Tile { + description: qsTr("Sharps will be used in questions and answers. It has to be checked, if keys with sharps are used.") + + TcheckBox { + id: sharpsChB + + enabled: !(useKeysChB.checked && (loKeyCombo.currentIndex > 7 || (rangeKeysChB.checked && hiKeyCombo.currentIndex > 7))) + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("# - sharps") + checked: creator.withSharps + onClicked: creator.withSharps = checked + } + + } + + Tile { + description: qsTr("Flats will be used in questions and answers. It has to be checked, if keys with flats are used.") + + TcheckBox { + id: flatsChB + + enabled: !(useKeysChB.checked && (loKeyCombo.currentIndex < 7 || (rangeKeysChB.checked && hiKeyCombo.currentIndex < 7))) + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("b - flats") + checked: creator.withFlats + onClicked: creator.withFlats = checked + } + + } + + Tile { + TcheckBox { + id: dblAccidsChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("x, bb - double accidentals") + checked: creator.withDblAccids + onClicked: creator.withDblAccids = checked + } + + } + + Tile { + description: qsTr("if checked, it is possible to select a note with given accidental only.") + + TcheckBox { + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("force using appropriate accidental") + checked: creator.forceAccids + onClicked: creator.forceAccids = checked + } + + } + } - } - description: qsTr("Select a key signature. Appropriate accidentals used in this level will be selected automatically.") - } - Tile { - enabled: useKeysChB.checked - TcheckBox { - text: qsTr("select a key signature manually") - anchors.horizontalCenter: parent.horizontalCenter - checked: creator.manualKey - onClicked: creator.manualKey = checked - } - description: qsTr("if checked, in exam user have to select a key signature, otherwise it is shown by application.") + // accids frame + } - CurrentKeyTile { - enabled: creator.howGetMelody !== 2 || !creator.isMelody - checked: creator.onlyCurrKey - checkBox.onClicked: creator.onlyCurrKey = checked - description: qsTr("Only notes from current key signature are taken. If key signature is disabled accidentals are not used.") + + Tframe { + id: keyFrame + + width: accidsGrid.columns === 1 ? parent.width * 0.98 : parent.width * 0.59 + + Column { + spacing: NOO.factor() / 2 + width: parent.width + + TcheckBox { + id: useKeysChB + + text: NOO.TR("ScorePage", "use key signatures") + anchors.horizontalCenter: parent.horizontalCenter + checked: creator.useKeySign + onClicked: creator.useKeySign = checked + } + + ButtonGroup { + id: keysGr + } + + Tile { + enabled: useKeysChB.checked + description: qsTr("Only one, selected key signature for whole exam.") + + TradioButton { + text: qsTr("single key") + ButtonGroup.group: keysGr + anchors.horizontalCenter: parent.horizontalCenter + checked: creator.isSingleKey + onClicked: creator.isSingleKey = checked + } + + } + + Tile { + enabled: useKeysChB.checked + description: qsTr("Random key signature from selected range.") + + TradioButton { + id: rangeKeysChB + + text: qsTr("range of keys") + ButtonGroup.group: keysGr + anchors.horizontalCenter: parent.horizontalCenter + checked: !creator.isSingleKey + onClicked: creator.isSingleKey = !checked + } + + } + + Tile { + enabled: useKeysChB.checked + description: qsTr("Select a key signature. Appropriate accidentals used in this level will be selected automatically.") + + Row { + spacing: NOO.factor() / 2 + anchors.horizontalCenter: parent.horizontalCenter + + TcomboBox { + id: loKeyCombo + + model: NOO.keyComboModel() + width: keyFrame.width * 0.4 + currentIndex: creator.loKey + 7 + onActivated: creator.loKey = currentIndex - 7 + } + + Rectangle { + color: enabled ? activPal.text : disdPal.text + width: NOO.factor() + height: NOO.factor() / 5 + anchors.verticalCenter: parent.verticalCenter + } + + TcomboBox { + id: hiKeyCombo + + enabled: rangeKeysChB.checked + model: NOO.keyComboModel() + width: keyFrame.width * 0.4 + currentIndex: creator.hiKey + 7 + onActivated: creator.hiKey = currentIndex - 7 + } + + } + + } + + Tile { + enabled: useKeysChB.checked + description: qsTr("if checked, in exam user have to select a key signature, otherwise it is shown by application.") + + TcheckBox { + text: qsTr("select a key signature manually") + anchors.horizontalCenter: parent.horizontalCenter + checked: creator.manualKey + onClicked: creator.manualKey = checked + } + + } + + CurrentKeyTile { + enabled: creator.howGetMelody !== 2 || !creator.isMelody + checked: creator.onlyCurrKey + checkBox.onClicked: creator.onlyCurrKey = checked + description: qsTr("Only notes from current key signature are taken. If key signature is disabled accidentals are not used.") + } + + } + // keyFrame + } - } - } // keyFrame - } + } + } diff --git a/src/qml/level/CurrentKeyTile.qml b/src/qml/level/CurrentKeyTile.qml index 9a4c027302560878c9c55c0f71e3f6d3de695c79..cc4812118bb04c4158ae9816cbe95af2502aa004 100644 --- a/src/qml/level/CurrentKeyTile.qml +++ b/src/qml/level/CurrentKeyTile.qml @@ -2,18 +2,18 @@ * Copyright (C) 2018 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" import QtQuick 2.12 -import "../" +Tile { + property alias checkBox: currKeyChB + property alias checked: currKeyChB.checked + TcheckBox { + id: currKeyChB -Tile { - property alias checkBox: currKeyChB - property alias checked: currKeyChB.checked + text: qsTranslate("AccidsPage", "notes in current key signature only") + anchors.horizontalCenter: parent.horizontalCenter + } - TcheckBox { - id: currKeyChB - text: qsTranslate("AccidsPage", "notes in current key signature only") - anchors.horizontalCenter: parent.horizontalCenter - } } diff --git a/src/qml/level/EndOnTonicTile.qml b/src/qml/level/EndOnTonicTile.qml index 8b850420ee7ce8ac82536f038f6492ec375710d5..2cf7bc22ac23f62b6626155bae5c124df5ed3d7a 100644 --- a/src/qml/level/EndOnTonicTile.qml +++ b/src/qml/level/EndOnTonicTile.qml @@ -2,22 +2,22 @@ * Copyright (C) 2018 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" import QtQuick 2.12 -import "../" +Tile { + property alias checkBox: tonicChB + property alias checked: tonicChB.checked + anchors.horizontalCenter: undefined + width: tonicChB.width * 1.2 + description: qsTr("Determines the last note of a melody.<br>When set, melody will be finished on tonic note in actual key signature.").replace("<br>", " ") -Tile { - property alias checkBox: tonicChB - property alias checked: tonicChB.checked + TcheckBox { + id: tonicChB - anchors.horizontalCenter: undefined - width: tonicChB.width * 1.2 - description: qsTr("Determines the last note of a melody.<br>When set, melody will be finished on tonic note in actual key signature.").replace("<br>", " ") - TcheckBox { - id: tonicChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("Melody ends on tonic note") - } -} + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Melody ends on tonic note") + } +} diff --git a/src/qml/level/LevelCreator.qml b/src/qml/level/LevelCreator.qml index ad4b02d0fd3c0043f7fc9d227ed4603b1de9c668..21874f4d0d0aba5b0a786a6fca3a2a10a0b04b95 100644 --- a/src/qml/level/LevelCreator.qml +++ b/src/qml/level/LevelCreator.qml @@ -2,60 +2,65 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 +import Nootka.Dialogs 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 -import Nootka.Dialogs 1.0 +TlevelCreatorItem { + id: creator + function help() { + NOO.openDocLink("2017/05/17/creating-levels/"); + } + + function reset() { + } + + width: parent.width + height: parent.height + Component.onCompleted: { + pages.addItem("levels", qsTr("Levels"), "level/Levels"); + pages.addItem("questionNote", qsTr("Questions"), "level/Questions"); + pages.addItem("melody", qsTr("Melody"), "level/Melody"); + pages.addItem("rhythms", qsTr("Rhythms"), "level/Rhythms"); + pages.addItem("accidentals", qsTr("Accidentals"), "level/Accids"); + pages.addItem("range", qsTr("Range"), "level/Range"); + dialLoader.title = title; + dialLoader.standardButtons = DialogButtonBox.Close | DialogButtonBox.Help | DialogButtonBox.RestoreDefaults; + var b = dialLoader.buttonBox.standardButton(DialogButtonBox.RestoreDefaults); + b.text = qsTr("Check"); + b.pixmap = NOO.pix("levelCreator"); + b.clicked.connect(checkLevel); + } + onSaveStateChanged: { + pages.buttons[0].pixmap = NOO.pix(notSaved ? "pane/notSaved" : "pane/levels"); + dialLoader.title = title; + } + onUpdateLevel: { + pages.buttons[1].pixmap = NOO.pix("pane/question" + (isMelody ? "Melody" : "Note")); + pages.buttons[2].enabled = isMelody; // melody button + pages.buttons[3].enabled = isMelody && howGetMelody != 2; // rhythms button (melody but not from the list) + pages.buttons[5].enabled = !isMelody || (isMelody && howGetMelody == 0); // range button + } + onSave: { + // save melody + + if (typeof (pages.pages[2]) !== "string") + pages.pages[2].saveLevel(); + + } + onWantValidationMessage: { + var c = Qt.createComponent("qrc:/level/LevelValidationMessage.qml"); + c.createObject(creator, { + "caption": title, + "message": message, + "accent": accent + }); + } + + PagesDialog { + id: pages + } -TlevelCreatorItem { - id: creator - - width: parent.width - height: parent.height - - PagesDialog { id: pages } - - Component.onCompleted: { - pages.addItem("levels", qsTr("Levels"), "level/Levels") - pages.addItem("questionNote", qsTr("Questions"), "level/Questions") - pages.addItem("melody", qsTr("Melody"), "level/Melody") - pages.addItem("rhythms", qsTr("Rhythms"), "level/Rhythms") - pages.addItem("accidentals", qsTr("Accidentals"), "level/Accids") - pages.addItem("range", qsTr("Range"), "level/Range") - - dialLoader.title = title - dialLoader.standardButtons = DialogButtonBox.Close | DialogButtonBox.Help | DialogButtonBox.RestoreDefaults - var b = dialLoader.buttonBox.standardButton(DialogButtonBox.RestoreDefaults) - b.text = qsTr("Check") - b.pixmap = NOO.pix("levelCreator") - b.clicked.connect(checkLevel) - } - - onSaveStateChanged: { - pages.buttons[0].pixmap = NOO.pix(notSaved ? "pane/notSaved" : "pane/levels") - dialLoader.title = title - } - - onUpdateLevel: { - pages.buttons[1].pixmap = NOO.pix("pane/question" + (isMelody ? "Melody" : "Note")) - pages.buttons[2].enabled = isMelody // melody button - pages.buttons[3].enabled = isMelody && howGetMelody != 2 // rhythms button (melody but not from the list) - pages.buttons[5].enabled = !isMelody || (isMelody && howGetMelody == 0) // range button - } - - onSave: { - if (typeof(pages.pages[2]) !== "string") // save melody - pages.pages[2].saveLevel() - } - - onWantValidationMessage: { - var c = Qt.createComponent("qrc:/level/LevelValidationMessage.qml") - c.createObject(creator, { "caption": title, "message": message, "accent": accent }) - } - - function help() { NOO.openDocLink("2017/05/17/creating-levels/") } - - function reset() {} } diff --git a/src/qml/level/LevelPreview.qml b/src/qml/level/LevelPreview.qml index 357717f0c579a3dccdb932bd4a7fa2da804565d0..06b5be0042fd7b62c9800df979084926fa68ba14 100644 --- a/src/qml/level/LevelPreview.qml +++ b/src/qml/level/LevelPreview.qml @@ -2,235 +2,354 @@ * Copyright (C) 2017-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 Nootka 1.0 import Nootka.Dialogs 1.0 -import "../" - +import QtQuick 2.12 TlevelPreviewItem { - id: levelPrev - - Rectangle { - anchors.fill: parent - color: activPal.base - Text { - color: Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 50)) - font { family: "Nootka"; pixelSize: Math.min(parent.width, parent.height) * 0.75 } - anchors.centerIn: parent - text: instrumentGlyph + id: levelPrev + + property real maxLabelWidth: NOO.factor() * 10 + property real maxValueWidth: NOO.factor() * 10 + + function zoom(zoomIn) { + if (!zoomTimer.running) { + var sc = levCol.scale * (zoomIn ? 1.0625 : 0.9375); + if (sc < 0.5 || sc > 2.5) + return ; + + levCol.scale = sc; + zoomTimer.running = true; + } } - PinchArea { - anchors.fill: parent - pinch.target: levCol - pinch.minimumScale: 0.5 - pinch.maximumScale: 2.0 - pinch.dragAxis: Pinch.XandYAxis - onPinchFinished: viewFlick.returnToBounds() - // HACK: keeping MouseArea inside PinchArea makes it working - MouseArea { + + Rectangle { anchors.fill: parent - onWheel: { - if (wheel.modifiers & Qt.ControlModifier) { - if (wheel.angleDelta.y > 0) - zoom(true) - else if (wheel.angleDelta.y < 0) - zoom(false) - } else - wheel.accepted = false + color: activPal.base + + Text { + color: Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 50)) + anchors.centerIn: parent + text: instrumentGlyph + + font { + family: "Nootka" + pixelSize: Math.min(parent.width, parent.height) * 0.75 + } + } - } + + PinchArea { + anchors.fill: parent + pinch.target: levCol + pinch.minimumScale: 0.5 + pinch.maximumScale: 2 + pinch.dragAxis: Pinch.XandYAxis + onPinchFinished: viewFlick.returnToBounds() + + // HACK: keeping MouseArea inside PinchArea makes it working + MouseArea { + anchors.fill: parent + onWheel: { + if (wheel.modifiers & Qt.ControlModifier) { + if (wheel.angleDelta.y > 0) + zoom(true); + else if (wheel.angleDelta.y < 0) + zoom(false); + } else { + wheel.accepted = false; + } + } + } + + } + } - } - - property real maxLabelWidth: NOO.factor() * 10 - property real maxValueWidth: NOO.factor() * 10 - - Tflickable { - id: viewFlick - anchors.fill: parent - contentWidth: Math.max(viewFlick.width, levCol.width * levCol.scale) - contentHeight: levCol.height * levCol.scale - Column { - id: levCol - topPadding: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - transformOrigin: Item.Top - scale: NOO.bound(0.5, viewFlick.width / (levRow.width + NOO.factor()), 1.2) - - PreviewItem { - textItem2.horizontalAlignment: Text.AlignHCenter - text2: header - } - - Item { width: 10; height: NOO.factor() } - - Rectangle { - visible: validLevel - width: levRow.width; height: NOO.factor() / 6 - color: activPal.text - anchors.horizontalCenter: parent.horizontalCenter - } - - Row { - id: levRow - visible: validLevel - anchors.horizontalCenter: parent.horizontalCenter - Rectangle { width: NOO.factor() / 6; height: levRow.height; color: activPal.text } - Column { - PreviewItem { text2: instrument } - Rectangle { width: parent.width; height: NOO.factor() / 12; color: activPal.text } - - PreviewItem { - id: noteRangeIt - index: 1 - handleWidth: true - height: NOO.factor() * 2 - text: NOO.TR("RangePage", "note range:").replace(":", " ") - text2: noteRange - textItem2.font { family: "Scorek"; pixelSize: NOO.factor() * 1.6 } - textItem2.y: NOO.factor() * -1.8 - } - - PreviewItem { - id: fretRangeIt - aboveItem: noteRangeIt - handleWidth: true - text: NOO.TR("RangePage", "fret range:").replace(":", " ") - text2: fretRange - } - - PreviewItem { - id: keyRangeIt - aboveItem: fretRangeIt - handleWidth: true - text: qsTranslate("TlevelPreviewItem", "key signature:").replace(":", " ") - text2: keyRange - textItem2.font.bold: true - } - - PreviewItem { - id: accidentalsIt - aboveItem: keyRangeIt - handleWidth: true - text: NOO.TR("AccidsPage", "accidentals") + " " - text2: accidentals === "" ? qsTranslate("TlevelPreviewItem", "none") : accidentals - textItem2.font { family: accidentals === "" ? NOO.fontFamily() : "Nootka"; pixelSize: NOO.factor() * (accidentals === "" ? 1 : 1.7) } - } - - PreviewItem { - id: questionsIt - aboveItem: accidentalsIt - handleWidth: true - text: NOO.TR("LevelCreator", "Questions") + " " - text2: questions === "" ? qsTr("not selected") : questions - textItem2.color: questions === "" ? "red" : activPal.text - textItem2.font { family: questions === "" ? NOO.fontFamily() : "Nootka"; pixelSize: NOO.factor() * (questions === "" ? 1 : 2) } - } - - PreviewItem { - id: answersIt - aboveItem: questionsIt - handleWidth: true - text: qsTranslate("LevelCreator", "Answers") + " " - text2: answers === "" ? qsTr("not selected") : answers - textItem2.color: answers === "" ? "red" : activPal.text - textItem2.font { family: answers === "" ? NOO.fontFamily() : "Nootka"; pixelSize: NOO.factor() * (answers === "" ? 1 : 2) } - } - - PreviewItem { - id: melodyIt - aboveItem: answersIt - textItem.font { family: "Nootka"; pixelSize: NOO.factor() * 2 } - textItem { width: maxLabelWidth - NOO.factor(); horizontalAlignment: Text.AlignHCenter } - text: "m" - handleWidth: true - text2: melodyFrom - } - - PreviewItem { - id: octaveIt - aboveItem: melodyIt - text: " " - width: answersIt.width - text2: requireOctave - textItem2 { width: width; horizontalAlignment: Text.AlignHCenter } - showBottomLine: true - } - - PreviewItem { - id: rhythmsIt - aboveItem: octaveIt - text: " " - width: answersIt.width - text2: useRhythms - textItem2 { width: width; horizontalAlignment: Text.AlignHCenter } - //showBottomLine: true - } - } // Column - - Rectangle { width: NOO.factor() / 6; height: levRow.height; color: activPal.text } + Tflickable { + id: viewFlick + + anchors.fill: parent + contentWidth: Math.max(viewFlick.width, levCol.width * levCol.scale) + contentHeight: levCol.height * levCol.scale Column { - PreviewItem { - layHorizontal: false - height: textItem2.height * (text2 === "\ue047" ? 1 : 0.75); textItem2.y: NOO.factor() - text: "<br>" + qsTranslate("TlevelPreviewItem", "Clef") + ":" - textItem2.font { family: "Scorek"; pixelSize: NOO.factor() * 4 } - text2: clef - } + id: levCol + + topPadding: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + transformOrigin: Item.Top + scale: NOO.bound(0.5, viewFlick.width / (levRow.width + NOO.factor()), 1.2) + + PreviewItem { + textItem2.horizontalAlignment: Text.AlignHCenter + text2: header + } + + Item { + width: 10 + height: NOO.factor() + } + + Rectangle { + visible: validLevel + width: levRow.width + height: NOO.factor() / 6 + color: activPal.text + anchors.horizontalCenter: parent.horizontalCenter + } + + Row { + id: levRow + + visible: validLevel + anchors.horizontalCenter: parent.horizontalCenter + + Rectangle { + width: NOO.factor() / 6 + height: levRow.height + color: activPal.text + } + + Column { + PreviewItem { + text2: instrument + } + + Rectangle { + width: parent.width + height: NOO.factor() / 12 + color: activPal.text + } + + PreviewItem { + id: noteRangeIt + + index: 1 + handleWidth: true + height: NOO.factor() * 2 + text: NOO.TR("RangePage", "note range:").replace(":", " ") + text2: noteRange + textItem2.y: NOO.factor() * -1.8 + + textItem2.font { + family: "Scorek" + pixelSize: NOO.factor() * 1.6 + } + + } + + PreviewItem { + id: fretRangeIt + + aboveItem: noteRangeIt + handleWidth: true + text: NOO.TR("RangePage", "fret range:").replace(":", " ") + text2: fretRange + } + + PreviewItem { + id: keyRangeIt + + aboveItem: fretRangeIt + handleWidth: true + text: qsTranslate("TlevelPreviewItem", "key signature:").replace(":", " ") + text2: keyRange + textItem2.font.bold: true + } + + PreviewItem { + id: accidentalsIt + + aboveItem: keyRangeIt + handleWidth: true + text: NOO.TR("AccidsPage", "accidentals") + " " + text2: accidentals === "" ? qsTranslate("TlevelPreviewItem", "none") : accidentals + + textItem2.font { + family: accidentals === "" ? NOO.fontFamily() : "Nootka" + pixelSize: NOO.factor() * (accidentals === "" ? 1 : 1.7) + } + + } + + PreviewItem { + id: questionsIt + + aboveItem: accidentalsIt + handleWidth: true + text: NOO.TR("LevelCreator", "Questions") + " " + text2: questions === "" ? qsTr("not selected") : questions + textItem2.color: questions === "" ? "red" : activPal.text + + textItem2.font { + family: questions === "" ? NOO.fontFamily() : "Nootka" + pixelSize: NOO.factor() * (questions === "" ? 1 : 2) + } + + } + + PreviewItem { + id: answersIt + + aboveItem: questionsIt + handleWidth: true + text: qsTranslate("LevelCreator", "Answers") + " " + text2: answers === "" ? qsTr("not selected") : answers + textItem2.color: answers === "" ? "red" : activPal.text + + textItem2.font { + family: answers === "" ? NOO.fontFamily() : "Nootka" + pixelSize: NOO.factor() * (answers === "" ? 1 : 2) + } + + } + + PreviewItem { + id: melodyIt + + aboveItem: answersIt + text: "m" + handleWidth: true + text2: melodyFrom + + textItem.font { + family: "Nootka" + pixelSize: NOO.factor() * 2 + } + + textItem { + width: maxLabelWidth - NOO.factor() + horizontalAlignment: Text.AlignHCenter + } + + } + + PreviewItem { + id: octaveIt + + aboveItem: melodyIt + text: " " + width: answersIt.width + text2: requireOctave + showBottomLine: true + + textItem2 { + width: width + horizontalAlignment: Text.AlignHCenter + } + + } + + PreviewItem { + id: rhythmsIt + + aboveItem: octaveIt + text: " " + width: answersIt.width + text2: useRhythms + + textItem2 { + width: width + horizontalAlignment: Text.AlignHCenter + } + //showBottomLine: true + + } + // Column + + } + + Rectangle { + width: NOO.factor() / 6 + height: levRow.height + color: activPal.text + } + + Column { + PreviewItem { + layHorizontal: false + height: textItem2.height * (text2 === "\ue047" ? 1 : 0.75) + textItem2.y: NOO.factor() + text: "<br>" + qsTranslate("TlevelPreviewItem", "Clef") + ":" + text2: clef + + textItem2.font { + family: "Scorek" + pixelSize: NOO.factor() * 4 + } + + } + + } + + Rectangle { + width: NOO.factor() / 6 + height: levRow.height + color: activPal.text + } + // levRow Row + + } + + Rectangle { + visible: validLevel + width: levRow.width + height: NOO.factor() / 6 + color: activPal.text + anchors.horizontalCenter: parent.horizontalCenter + } + + Item { + width: 10 + height: NOO.factor() + } + + PreviewItem { + visible: validLevel + text: " " + textItem2.width: levelPrev.width * 0.9 / levCol.scale + textItem2.wrapMode: Text.WordWrap + text2: description.replace("\n", "<br>") + } + // levCol Column + } - Rectangle { width: NOO.factor() / 6; height: levRow.height; color: activPal.text } - } // levRow Row - - Rectangle { - visible: validLevel - width: levRow.width; height: NOO.factor() / 6 - color: activPal.text - anchors.horizontalCenter: parent.horizontalCenter - } - - Item { width: 10; height: NOO.factor() } - - PreviewItem { - visible: validLevel - text: " " - textItem2.width: levelPrev.width * 0.9 / levCol.scale - textItem2.wrapMode: Text.WordWrap - text2: description.replace("\n", "<br>") - } - } // levCol Column - } - - Timer { id: zoomTimer; interval: 100 } - - Row { // no zoom buttons under Android - visible: !NOO.isAndroid() - anchors { right: parent.right; bottom: parent.bottom } - HeadButton { - factor: NOO.factor() / 3; hiHover: false - height: factor * 9.5 - pixmap: NOO.pix("zoom-out") - onClicked: zoom(false) } - HeadButton { - factor: NOO.factor() / 3; hiHover: false - height: factor * 9.5 - pixmap: NOO.pix("zoom-in") - onClicked: zoom(true) + + Timer { + id: zoomTimer + + interval: 100 } - } - - function zoom(zoomIn) { - if (!zoomTimer.running) { - var sc = levCol.scale * (zoomIn ? 1.0625 : 0.9375) - if (sc < 0.5 || sc > 2.5) - return - levCol.scale = sc - zoomTimer.running = true + + // no zoom buttons under Android + Row { + visible: !NOO.isAndroid() + + anchors { + right: parent.right + bottom: parent.bottom + } + + HeadButton { + factor: NOO.factor() / 3 + hiHover: false + height: factor * 9.5 + pixmap: NOO.pix("zoom-out") + onClicked: zoom(false) + } + + HeadButton { + factor: NOO.factor() / 3 + hiHover: false + height: factor * 9.5 + pixmap: NOO.pix("zoom-in") + onClicked: zoom(true) + } + } - } + } diff --git a/src/qml/level/LevelValidationMessage.qml b/src/qml/level/LevelValidationMessage.qml index 070edaf5a96c8842bde4dfb2b5528bab44030f70..f3ea7186ea60f8bad12f9e0820e3023cbe88cd6c 100644 --- a/src/qml/level/LevelValidationMessage.qml +++ b/src/qml/level/LevelValidationMessage.qml @@ -2,48 +2,65 @@ * Copyright (C) 2020-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - -import Nootka 1.0 import "../" +import Nootka 1.0 +import QtQuick 2.12 TpopupDialog { - property alias message: lv.model - property color accent: activPal.highlight - - bgColor: Qt.tint(activPal.base, NOO.alpha(accent, 20)) - border { color: accent; width: NOO.factor() / 4.0 } - visible: true; modal: true - width: lv.width + NOO.factor() / 2 - height: lv.height + header.height + footer.height + NOO.factor() - glowRect.radius: NOO.factor() - - rejectButton.visible: false - acceptButton.text: NOO.TR("QPlatformTheme", "OK") - acceptButton.visible: !NOO.isAndroid() - - ListView { - id: lv - width: NOO.factor() * 40; height: contentHeight - spacing: 2; clip: true - delegate: Rectangle { - width: lv.width; height: mText.height + NOO.factor() / 2 - color: index % 2 === 1 ? "transparent" : NOO.alpha(activPal.base, 50) - Rectangle { - width: NOO.factor() / 2; height: width; radius: width / 2 - x: NOO.factor() / 2; y: (parent.height - height) / 2 - color: activPal.text - } - Text { - id: mText - x: NOO.factor() * 1.5; y: (parent.height - height) / 2 - width: lv.width - NOO.factor() * 2 - wrapMode: Text.WordWrap - text: modelData - font.pixelSize: NOO.factor() - } + property alias message: lv.model + property color accent: activPal.highlight + + bgColor: Qt.tint(activPal.base, NOO.alpha(accent, 20)) + visible: true + modal: true + width: lv.width + NOO.factor() / 2 + height: lv.height + header.height + footer.height + NOO.factor() + glowRect.radius: NOO.factor() + rejectButton.visible: false + acceptButton.text: NOO.TR("QPlatformTheme", "OK") + acceptButton.visible: !NOO.isAndroid() + onClosed: destroy() + + border { + color: accent + width: NOO.factor() / 4 + } + + ListView { + id: lv + + width: NOO.factor() * 40 + height: contentHeight + spacing: 2 + clip: true + + delegate: Rectangle { + width: lv.width + height: mText.height + NOO.factor() / 2 + color: index % 2 === 1 ? "transparent" : NOO.alpha(activPal.base, 50) + + Rectangle { + width: NOO.factor() / 2 + height: width + radius: width / 2 + x: NOO.factor() / 2 + y: (parent.height - height) / 2 + color: activPal.text + } + + Text { + id: mText + + x: NOO.factor() * 1.5 + y: (parent.height - height) / 2 + width: lv.width - NOO.factor() * 2 + wrapMode: Text.WordWrap + text: modelData + font.pixelSize: NOO.factor() + } + + } + } - } - onClosed: destroy() } diff --git a/src/qml/level/Levels.qml b/src/qml/level/Levels.qml index 226f7eaecd5f832677b8fc5963eb0a11358824f1..40886c633acb223e407e0b3fd75233fe19d260ef 100644 --- a/src/qml/level/Levels.qml +++ b/src/qml/level/Levels.qml @@ -4,7 +4,6 @@ import QtQuick 2.12 - /** * This QML file is fake... * It exists only to be parsed by lupdate! @@ -14,20 +13,9 @@ import QtQuick 2.12 * So 'Levels' is translation context where lupdate will put the texts in. */ Item { - property string name1: qsTr("J. S. Bach - Minuet") - property string desc1: qsTr("Play melody of J. S. Bach Minuet from Notebook for Anna Magdalena Bach divided into smaller parts.") - - property string name2: qsTr("Simple melodies") - property string desc2: qsTr("Play popular, simple melodies on your instrument.") - - property var intonationTexts: [ - qsTranslate("TintonationCombo", "intonation accuracy"), - qsTranslate("TintonationCombo", "do not check"), - qsTranslate("TintonationCombo", "gums pain", "We used to say that gums or teeth are paining when music is out of tune but it isn't official term."), - qsTranslate("TintonationCombo", "violinist beginner"), - qsTranslate("TintonationCombo", "old strings"), - qsTranslate("TintonationCombo", "well tuned instrument"), - qsTranslate("TintonationCombo", "perfect"), - qsTranslate("TintonationCombo", "cents", "unit of measure used for musical intervals. This text always is used in context: ' ± [5, 10, 20, 30] cents '") - ] + property string name1: qsTr("J. S. Bach - Minuet") + property string desc1: qsTr("Play melody of J. S. Bach Minuet from Notebook for Anna Magdalena Bach divided into smaller parts.") + property string name2: qsTr("Simple melodies") + property string desc2: qsTr("Play popular, simple melodies on your instrument.") + property var intonationTexts: [qsTranslate("TintonationCombo", "intonation accuracy"), qsTranslate("TintonationCombo", "do not check"), qsTranslate("TintonationCombo", "gums pain", "We used to say that gums or teeth are paining when music is out of tune but it isn't official term."), qsTranslate("TintonationCombo", "violinist beginner"), qsTranslate("TintonationCombo", "old strings"), qsTranslate("TintonationCombo", "well tuned instrument"), qsTranslate("TintonationCombo", "perfect"), qsTranslate("TintonationCombo", "cents", "unit of measure used for musical intervals. This text always is used in context: ' ± [5, 10, 20, 30] cents '")] } diff --git a/src/qml/level/LevelsPage.qml b/src/qml/level/LevelsPage.qml index 23ce031a46c44651228f620c10a3b83a92bc8a6a..353bb81a3e7a65853a54179658cda2eff57e4d4b 100644 --- a/src/qml/level/LevelsPage.qml +++ b/src/qml/level/LevelsPage.qml @@ -2,148 +2,192 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - -import Nootka 1.0 import "../" - +import Nootka 1.0 +import QtQuick 2.12 Column { - id: levelsPage + id: levelsPage - height: parent.height; width: parent.width + property var notSavedMess: null - spacing: levelsPage.width / 50 - LevelsSelector { - id: selector + function start(action, argument) { + GLOB.isExam = true; + nootkaWindow.executor.init(action, argument); + dialLoader.close(); + } + + height: parent.height width: parent.width - height: levelsPage.height - buttRow.height - levelsPage.width / 25 - (NOO.isAndroid() ? 0 : NOO.factor() * 3) - Component.onCompleted: creator.selector = selector - } - Row { - id: buttRow spacing: levelsPage.width / 50 - anchors.horizontalCenter: parent.horizontalCenter - TiconButton { - enabled: creator.notSaved - width: levelsPage.width / 4 - pixmap: NOO.pix("save"); iconHeight: levelsPage.height / 15 - text: NOO.TR("QShortcut", "Save") - onClicked: creator.saveLevel() - } - TiconButton { - enabled: selector.levelId !== -1 && selector.isSuitable(selector.levelId) - width: levelsPage.width / 4 - pixmap: NOO.pix("exam"); iconHeight: levelsPage.height / 15 - text: qsTr("Start exam") - onClicked: start(2, selector.currentLevelVar()) - } - TiconButton { - enabled: selector.levelId !== -1 && selector.isSuitable(selector.levelId) - width: levelsPage.width / 4 - pixmap: NOO.pix("practice"); iconHeight: levelsPage.height / 15 - text: qsTr("Start exercise") - onClicked: start(4, selector.currentLevelVar()) + + LevelsSelector { + id: selector + + width: parent.width + height: levelsPage.height - buttRow.height - levelsPage.width / 25 - (NOO.isAndroid() ? 0 : NOO.factor() * 3) + Component.onCompleted: creator.selector = selector } - } - LinkText { - visible: !NOO.isAndroid() - text: qsTr("Get more levels <a href=\"%1\">from Nootka home page</a>").arg("https://nootka.sourceforge.io/index.php/download/#levels") - anchors.horizontalCenter: parent.horizontalCenter - } - - function start(action, argument) { - GLOB.isExam = true - nootkaWindow.executor.init(action, argument) - dialLoader.close() - } - - property var notSavedMess: null - Connections { - target: creator - onSaveNewLevel: { - newLevelPopup.name = name === "" ? qsTr("new level") : name - newLevelPopup.desc = desc - newLevelPopup.open() + + Row { + id: buttRow + + spacing: levelsPage.width / 50 + anchors.horizontalCenter: parent.horizontalCenter + + TiconButton { + enabled: creator.notSaved + width: levelsPage.width / 4 + pixmap: NOO.pix("save") + iconHeight: levelsPage.height / 15 + text: NOO.TR("QShortcut", "Save") + onClicked: creator.saveLevel() + } + + TiconButton { + enabled: selector.levelId !== -1 && selector.isSuitable(selector.levelId) + width: levelsPage.width / 4 + pixmap: NOO.pix("exam") + iconHeight: levelsPage.height / 15 + text: qsTr("Start exam") + onClicked: start(2, selector.currentLevelVar()) + } + + TiconButton { + enabled: selector.levelId !== -1 && selector.isSuitable(selector.levelId) + width: levelsPage.width / 4 + pixmap: NOO.pix("practice") + iconHeight: levelsPage.height / 15 + text: qsTr("Start exercise") + onClicked: start(4, selector.currentLevelVar()) + } + } - onWantNotSavedMessage: { - if (!notSavedMess) { - notSavedMess = Qt.createComponent("qrc:/Tmessage.qml").createObject(creator, { "accent": "#ff557f" }) - notSavedMess.rejectButton.visible = true - notSavedMess.acceptButton.text = NOO.TR("QShortcut", "Save") - notSavedMess.rejectButton.text = NOO.TR("QPlatformTheme", "Discard") - notSavedMess.acceptButton.pixmap = NOO.pix("pane/notSaved") - notSavedMess.accepted.connect(creator.saveLevel) - notSavedMess.rejected.connect(creator.resumeAfterLevelChange) // discard button clicked - notSavedMess.discarded.connect(creator.resumeAfterLevelChange) // when clicked out of popup - } - notSavedMess.caption = title - notSavedMess.message = message - notSavedMess.open() + + LinkText { + visible: !NOO.isAndroid() + text: qsTr("Get more levels <a href=\"%1\">from Nootka home page</a>").arg("https://nootka.sourceforge.io/index.php/download/#levels") + anchors.horizontalCenter: parent.horizontalCenter } - } - - TpopupDialog { - id: newLevelPopup - property alias name: lName.text - property alias desc: lDesc.text - - modal: true - width: popCol.width + NOO.factor() * 2; height: popCol.height + NOO.factor() * 5 - x: (parent.width - width) / 2; y: NOO.isAndroid() ? NOO.factor() : (parent.height - height) / 2 - bgColor: Qt.tint(activPal.window, NOO.alpha(activPal.highlight, 30)) - border { color: activPal.highlight; width: NOO.factor() / 4.0 } - glowRect.radius: NOO.factor() - - rejectButton.text: NOO.TR("QPlatformTheme", "Discard") - acceptButton.text: NOO.TR("QShortcut", "Save") - acceptButton.pixmap: NOO.pix("pane/notSaved") - - Column { - id: popCol - anchors.centerIn: parent - spacing: NOO.factor() - Row { - anchors { right: parent.right; rightMargin: NOO.factor() / 2 } - spacing: NOO.factor() - Text { - anchors.verticalCenter: parent.verticalCenter - color: activPal.text - text: qsTr("Level name:") + + Connections { + target: creator + onSaveNewLevel: { + newLevelPopup.name = name === "" ? qsTr("new level") : name; + newLevelPopup.desc = desc; + newLevelPopup.open(); } - TtextField { - id: lName - maximumLength: 36 - width: NOO.factor() * 27 + onWantNotSavedMessage: { + if (!notSavedMess) { + notSavedMess = Qt.createComponent("qrc:/Tmessage.qml").createObject(creator, { + "accent": "#ff557f" + }); + notSavedMess.rejectButton.visible = true; + notSavedMess.acceptButton.text = NOO.TR("QShortcut", "Save"); + notSavedMess.rejectButton.text = NOO.TR("QPlatformTheme", "Discard"); + notSavedMess.acceptButton.pixmap = NOO.pix("pane/notSaved"); + notSavedMess.accepted.connect(creator.saveLevel); + notSavedMess.rejected.connect(creator.resumeAfterLevelChange); // discard button clicked + notSavedMess.discarded.connect(creator.resumeAfterLevelChange); // when clicked out of popup + } + notSavedMess.caption = title; + notSavedMess.message = message; + notSavedMess.open(); } - } - Text { - color: activPal.text - text: qsTr("Level description:") - } - GlowRect { - id: bg - anchors.horizontalCenter: parent.horizontalCenter - width: newLevelPopup.width - NOO.factor() * 2; height: NOO.factor() * 6.5 - border { width: lDesc.focus ? 1 : 0; color: activPal.highlight } - color: activPal.base - TextEdit { - id: lDesc - width: parent.width - NOO.factor(); height: NOO.factor() * 6 - anchors.centerIn: parent - selectByMouse: true - selectedTextColor: activPal.highlightedText - selectionColor: activPal.highlight - wrapMode: TextEdit.WordWrap - onLengthChanged: { - if (length > 255) - text = text.substr(-255) - } + } + + TpopupDialog { + id: newLevelPopup + + property alias name: lName.text + property alias desc: lDesc.text + + modal: true + width: popCol.width + NOO.factor() * 2 + height: popCol.height + NOO.factor() * 5 + x: (parent.width - width) / 2 + y: NOO.isAndroid() ? NOO.factor() : (parent.height - height) / 2 + bgColor: Qt.tint(activPal.window, NOO.alpha(activPal.highlight, 30)) + glowRect.radius: NOO.factor() + rejectButton.text: NOO.TR("QPlatformTheme", "Discard") + acceptButton.text: NOO.TR("QShortcut", "Save") + acceptButton.pixmap: NOO.pix("pane/notSaved") + onAccepted: creator.continueLevelSave(name, desc) + onRejected: creator.resumeAfterLevelChange() + + border { + color: activPal.highlight + width: NOO.factor() / 4 } - } + + Column { + id: popCol + + anchors.centerIn: parent + spacing: NOO.factor() + + Row { + spacing: NOO.factor() + + anchors { + right: parent.right + rightMargin: NOO.factor() / 2 + } + + Text { + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + text: qsTr("Level name:") + } + + TtextField { + id: lName + + maximumLength: 36 + width: NOO.factor() * 27 + } + + } + + Text { + color: activPal.text + text: qsTr("Level description:") + } + + GlowRect { + id: bg + + anchors.horizontalCenter: parent.horizontalCenter + width: newLevelPopup.width - NOO.factor() * 2 + height: NOO.factor() * 6.5 + color: activPal.base + + border { + width: lDesc.focus ? 1 : 0 + color: activPal.highlight + } + + TextEdit { + id: lDesc + + width: parent.width - NOO.factor() + height: NOO.factor() * 6 + anchors.centerIn: parent + selectByMouse: true + selectedTextColor: activPal.highlightedText + selectionColor: activPal.highlight + wrapMode: TextEdit.WordWrap + onLengthChanged: { + if (length > 255) + text = text.substr(-255); + + } + } + + } + + } + } - onAccepted: creator.continueLevelSave(name, desc) - onRejected: creator.resumeAfterLevelChange() - } } diff --git a/src/qml/level/LevelsSelector.qml b/src/qml/level/LevelsSelector.qml index a380277aac73fe5bb9f09bcb9417c5ffc30f5b08..006c315eabbcea5eeef84dce4ea9fb75ac62bca2 100644 --- a/src/qml/level/LevelsSelector.qml +++ b/src/qml/level/LevelsSelector.qml @@ -2,129 +2,172 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 -import QtQuick.Controls 2.12 - +import "../" import Nootka 1.0 import Nootka.Dialogs 1.0 -import "../" - +import QtQuick 2.12 +import QtQuick.Controls 2.12 TlevelsSelector { - id: lSelector + id: lSelector - property alias levelId: view.currentIndex + property alias levelId: view.currentIndex + // private + property bool isVertical: parent.height * 1.2 > parent.width - levelPreview: previewItem - currentIndex: view.currentIndex + function rmLevelSlot(fromDisk) { + if (removeLevel(view.currentIndex, fromDisk)) + view.currentIndex = -1; - onSelectLast: view.currentIndex = view.count - 1 + } + + levelPreview: previewItem + currentIndex: view.currentIndex + onSelectLast: view.currentIndex = view.count - 1 + onWarnMessage: { + Qt.createComponent("qrc:/Tmessage.qml").createObject(lSelector.parent, { + "message": message, + "accent": accent + }); + } - // private - property bool isVertical: parent.height * 1.2 > parent.width + Grid { + width: parent.width + columns: isVertical ? 1 : 2 + spacing: width / 100 + padding: width / 200 - Grid { - width: parent.width - columns: isVertical ? 1 : 2 - spacing: width / 100 - padding: width / 200 + Column { + width: lSelector.width * (isVertical ? 1 : 0.49) + spacing: Math.min(lSelector.width, lSelector.height) / 100 - Column { - width: lSelector.width * (isVertical ? 1 : 0.49 ) - spacing: Math.min(lSelector.width, lSelector.height) / 100 + ListView { + id: view - ListView { - id: view - clip: true - width: parent.width - height: lSelector.height * (isVertical ? 0.48 : 0.96) - buttRow.height - spacing: 1 - currentIndex: -1 - ScrollBar.vertical: ScrollBar { active: false; visible: active } - model: levelsModel - delegate: Rectangle { - width: view.width; height: delegateRow.height - color: index === view.currentIndex ? activPal.highlight : - (area.containsMouse ? Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 50)) : (index % 2 === 1 ? activPal.alternateBase : activPal.base)) - Row { - id: delegateRow - width: parent.width - padding: width / 100 - Text { - anchors.verticalCenter: parent.verticalCenter - font { family: "Nootka"; pixelSize: NOO.factor() * 1.7 } - width: NOO.factor() * 2.5 - color: index === view.currentIndex ? activPal.highlightedText : isMelody(index) ? NOO.invert(activPal.highlight) : activPal.highlight - text: isMelody(index) ? "m" : "n" - horizontalAlignment: Text.AlignHCenter - } - Column { - width: parent.width - NOO.factor() * 3 - spacing: NOO.factor() / 4 - anchors.verticalCenter: parent.verticalCenter - Text { + clip: true width: parent.width - font { pixelSize: NOO.factor(); bold: true } - text: modelData - color: index === view.currentIndex ? activPal.highlightedText : (isSuitable(index) ? activPal.text : disdPal.text) - elide: Text.ElideRight - } - Text { - visible: text !== "" - width: parent.width - text: desc(index) - font.pixelSize: NOO.factor() * 0.8 - color: index === view.currentIndex ? activPal.highlightedText : activPal.text - wrapMode: Text.WordWrap; maximumLineCount: 2; elide: Text.ElideRight - } + height: lSelector.height * (isVertical ? 0.48 : 0.96) - buttRow.height + spacing: 1 + currentIndex: -1 + model: levelsModel + + ScrollBar.vertical: ScrollBar { + active: false + visible: active + } + + delegate: Rectangle { + width: view.width + height: delegateRow.height + color: index === view.currentIndex ? activPal.highlight : (area.containsMouse ? Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 50)) : (index % 2 === 1 ? activPal.alternateBase : activPal.base)) + + Row { + id: delegateRow + + width: parent.width + padding: width / 100 + + Text { + anchors.verticalCenter: parent.verticalCenter + width: NOO.factor() * 2.5 + color: index === view.currentIndex ? activPal.highlightedText : isMelody(index) ? NOO.invert(activPal.highlight) : activPal.highlight + text: isMelody(index) ? "m" : "n" + horizontalAlignment: Text.AlignHCenter + + font { + family: "Nootka" + pixelSize: NOO.factor() * 1.7 + } + + } + + Column { + width: parent.width - NOO.factor() * 3 + spacing: NOO.factor() / 4 + anchors.verticalCenter: parent.verticalCenter + + Text { + width: parent.width + text: modelData + color: index === view.currentIndex ? activPal.highlightedText : (isSuitable(index) ? activPal.text : disdPal.text) + elide: Text.ElideRight + + font { + pixelSize: NOO.factor() + bold: true + } + + } + + Text { + visible: text !== "" + width: parent.width + text: desc(index) + font.pixelSize: NOO.factor() * 0.8 + color: index === view.currentIndex ? activPal.highlightedText : activPal.text + wrapMode: Text.WordWrap + maximumLineCount: 2 + elide: Text.ElideRight + } + + } + + } + + MouseArea { + id: area + + anchors.fill: parent + hoverEnabled: true + onClicked: { + view.currentIndex = index; + showLevel(index); + } + } + // Rectangle + + } + } - } - MouseArea { - anchors.fill: parent - id: area - hoverEnabled: true - onClicked: { - view.currentIndex = index - showLevel(index) + + Row { + id: buttRow + + anchors.horizontalCenter: parent.horizontalCenter + spacing: lSelector.width / 50 + + TiconButton { + pixmap: NOO.pix("nootka-level") + text: qsTr("Load") + onClicked: loadFromFile() + } + + TiconButton { + enabled: isRemovable(view.currentIndex) + pixmap: NOO.pix("delete") + text: NOO.TR("QFileDialog", "Remove") + onClicked: { + var c = Qt.createComponent("qrc:/level/RemoveLevel.qml"); + var rmLevelDialog = c.createObject(lSelector, { + "levelName": levelName(view.currentIndex), + "levelFile": levelFile(view.currentIndex) + }); + rmLevelDialog.onRemove.connect(rmLevelSlot); + } + } + } - } - } // Rectangle - } - - Row { - id: buttRow - anchors.horizontalCenter: parent.horizontalCenter - spacing: lSelector.width / 50 - - TiconButton { - pixmap: NOO.pix("nootka-level"); text: qsTr("Load") - onClicked: loadFromFile() + // Column of level list + } - TiconButton { - enabled: isRemovable(view.currentIndex) - pixmap: NOO.pix("delete"); text: NOO.TR("QFileDialog", "Remove") - onClicked: { - var c = Qt.createComponent("qrc:/level/RemoveLevel.qml") - var rmLevelDialog = c.createObject(lSelector, { "levelName": levelName(view.currentIndex), "levelFile": levelFile(view.currentIndex) }) - rmLevelDialog.onRemove.connect(rmLevelSlot) - } + + LevelPreview { + id: previewItem + + width: lSelector.width * (isVertical ? 1 : 0.49) + height: lSelector.height * (isVertical ? 0.49 : 1) } - } - } // Column of level list - LevelPreview { - id: previewItem - width: lSelector.width * (isVertical ? 1 : 0.49 ) - height: lSelector.height * (isVertical ? 0.49 : 1) } - } - - function rmLevelSlot(fromDisk) { - if (removeLevel(view.currentIndex, fromDisk)) - view.currentIndex = -1 - } - onWarnMessage: { - Qt.createComponent("qrc:/Tmessage.qml").createObject(lSelector.parent, { "message": message, "accent": accent }) - } } diff --git a/src/qml/level/MaxIntervalTile.qml b/src/qml/level/MaxIntervalTile.qml index 034ec08c3f800b7d9894a1421572010d6648f8da..e0356893caae0d44874473834f9cf42021cd0e66 100644 --- a/src/qml/level/MaxIntervalTile.qml +++ b/src/qml/level/MaxIntervalTile.qml @@ -2,32 +2,37 @@ * 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 QtQuick.Controls 2.12 -import Nootka 1.0 -import "../" - Tile { - property alias maxStep: maxSpin.value - - signal maxModified() - - description: qsTr("Maximal interval between notes used in a melody (in semitones).") - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() / 2 - Text { - anchors.verticalCenter: parent.verticalCenter - text: qsTr("Max interval") - color: activPal.text - } - TspinBox { - id: maxSpin - from: 2; to: 36 - value: 0 - onValueModified: maxModified() + property alias maxStep: maxSpin.value + + signal maxModified() + + description: qsTr("Maximal interval between notes used in a melody (in semitones).") + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() / 2 + + Text { + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Max interval") + color: activPal.text + } + + TspinBox { + id: maxSpin + + from: 2 + to: 36 + value: 0 + onValueModified: maxModified() + } + } - } -} +} diff --git a/src/qml/level/MelodyListView.qml b/src/qml/level/MelodyListView.qml index d9cc1920a7dafefe6bceeacb23d653cd5d77b372..9f4a7cd1bfc157eadee095c29156514352d8d69f 100644 --- a/src/qml/level/MelodyListView.qml +++ b/src/qml/level/MelodyListView.qml @@ -2,224 +2,345 @@ * Copyright (C) 2018-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" +import "../score" +import Nootka 1.0 +import Nootka.Dialogs 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 - -import Nootka.Dialogs 1.0 -import Nootka 1.0 import Score 1.0 -import "../score" -import "../" - TmelodyListView { - id: melListView + id: melListView - implicitHeight: viewRow.height + property int currentMelody: -1 + property alias viewRoot: viewItem + property var melPreview: null + property var currWrapp: null + property var dividePop: null + property var transPop: null - property int currentMelody: -1 - property alias viewRoot: viewItem + function showMelody(wrappId) { + if (!melPreview) { + melPreview = Qt.createComponent("qrc:/score/MelodyPreview.qml").createObject(NOO.isAndroid() ? nootkaWindow : melPage, { + "width": (NOO.isAndroid() ? nootkaWindow.width : melListView.width) - NOO.factor() * 2, + "maxHeight": melPage.height - NOO.factor() * (NOO.isAndroid() ? 4 : 10) + }); + melPreview.wantDivide.connect(showDividePopup); + melPreview.wantTranspose.connect(showTransposePopup); + } + currWrapp = wrappId; + melPreview.open(); + melPreview.melody = getMelody(wrappId.nr); + melPreview.idText = (wrappId.nr + 1) + "."; + melPreview.border.color = wrappId.outOfScale ? "red" : activPal.highlight; + } - melodyModel: ListModel { id: melMod } + function removeWrapper(id) { + melMod.remove(id); + removeMelody(id); + currentMelody = -1; + } - Row { - id: viewRow - Text { - visible: !melView.visible - y: NOO.factor() * 2 - width: melListView.width - NOO.factor() * 4 - // TODO: Remove 2nd sentence from translations and here - text: qsTr("Add here melodies from Music XML files.\nBut better keep them short, so divide them first in some external software.").split(".")[0] + "." - horizontalAlignment: Text.AlignHCenter; wrapMode: Text.WordWrap - font { pixelSize: NOO.factor() * 1.2; bold: true } + function moveMelody(from, to) { + melMod.move(from, to, 1); + swapMelodies(from, to); } - Item { - id: viewItem - visible: melView.count > 0 - width: melListView.width - NOO.factor() * 4; height: Math.max(buttCol.height, melPage.height) //melListView.height - ListView { - id: melView - clip: true; spacing: 1 - anchors { fill: parent; margins: 5 } - add: Transition { - enabled: GLOB.useAnimations - NumberAnimation { property: "x"; from: -melListView.width; to: 0 } - } - remove: Transition { - enabled: GLOB.useAnimations - NumberAnimation { property: "x"; to: -melListView.width } - } - populate: Transition { - enabled: GLOB.useAnimations - NumberAnimation { property: "x"; from: -melListView.width; to: 0 } - } - move: Transition { - enabled: GLOB.useAnimations - NumberAnimation { property: "y" } - } - moveDisplaced: Transition { - enabled: GLOB.useAnimations - NumberAnimation { property: "y" } - } - model: melMod - delegate: MelodyWrapper { - nr: index - width: melView.width - 10 - Component.onCompleted: { - updateMelody() - } - } - } + + function showDividePopup() { + if (!dividePop) + dividePop = divideComp.createObject(melPage); + + dividePop.open(); } - Column { - id: buttCol - spacing: NOO.factor() * (NOO.isAndroid() ? 0.7 : 1) - leftPadding: NOO.factor() / 2; topPadding: NOO.factor() / (NOO.isAndroid() ? 2 : 1) - TcuteButton { - visible: NOO.isAndroid() - width: NOO.factor() * 3 - font { pixelSize: NOO.factor() * 2.5; family: "Nootka" } - text: "\u0191"; textColor: enabled ? activPal.highlight : disdPal.text - enabled: currentMelody > -1 - onClicked: showMelody(melView.currentItem) - } - Item { width: 1; height: NOO.factor() * (NOO.isAndroid() ? 0.25 : 1.5) } - TcuteButton { - width: NOO.factor() * 3 - font { pixelSize: NOO.factor() * 2.5; bold: true } - text: "+"; textColor: "green" - onClicked: { - loadMelody() - melView.positionViewAtEnd() - } - } - Item { width: 1; height: NOO.factor() * (NOO.isAndroid() ? 0.25 : 1.5) } - TcuteButton { - width: NOO.factor() * 3 - font { pixelSize: NOO.factor() * 2.5; family: "Nootka" } - text: "\u2191"; textColor: enabled ? "#008080" : disdPal.text - enabled: currentMelody > 0 - onClicked: { - moveMelody(currentMelody, currentMelody - 1) - currentMelody-- + + function showTransposePopup() { + if (!transPop) + transPop = transcomp.createObject(melPage); + + transPop.transpose.initialKey = currWrapp.wrapper.key; + transPop.open(); + } + + implicitHeight: viewRow.height + onAppendMelody: melMod.append({ + }) + onInsertMelody: melMod.insert(melId, { + }) + onMelodiesChanged: creator.melodyListChanged() + + Row { + id: viewRow + + Text { + visible: !melView.visible + y: NOO.factor() * 2 + width: melListView.width - NOO.factor() * 4 + // TODO: Remove 2nd sentence from translations and here + text: qsTr("Add here melodies from Music XML files.\nBut better keep them short, so divide them first in some external software.").split(".")[0] + "." + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + + font { + pixelSize: NOO.factor() * 1.2 + bold: true + } + } - } - TcuteButton { - width: NOO.factor() * 3 - font { pixelSize: NOO.factor() * 2.5; family: "Nootka" } - text: "\u2193"; textColor: enabled ? "#008080" : disdPal.text - enabled: currentMelody > -1 && currentMelody < melMod.count - 1 - onClicked: { - moveMelody(currentMelody, currentMelody + 1) - currentMelody++ + + Item { + id: viewItem + + visible: melView.count > 0 + width: melListView.width - NOO.factor() * 4 //melListView.height + height: Math.max(buttCol.height, melPage.height) + + ListView { + id: melView + + clip: true + spacing: 1 + model: melMod + + anchors { + fill: parent + margins: 5 + } + + add: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "x" + from: -melListView.width + to: 0 + } + + } + + remove: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "x" + to: -melListView.width + } + + } + + populate: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "x" + from: -melListView.width + to: 0 + } + + } + + move: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "y" + } + + } + + moveDisplaced: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "y" + } + + } + + delegate: MelodyWrapper { + nr: index + width: melView.width - 10 + Component.onCompleted: { + updateMelody(); + } + } + + } + } - } - Item { width: 1; height: NOO.factor() * (NOO.isAndroid() ? 0.25 : 1.5) } - TcuteButton { - width: NOO.factor() * 3 - font { pixelSize: NOO.factor() * 2.5; bold: true } - text: "-"; textColor: enabled ? "red" : disdPal.text - enabled: currentMelody > -1 - onClicked: removeWrapper(currentMelody) - Shortcut { - enabled: currentMelody > -1 - sequence: "del" - onActivated: removeWrapper(currentMelody) + + Column { + id: buttCol + + spacing: NOO.factor() * (NOO.isAndroid() ? 0.7 : 1) + leftPadding: NOO.factor() / 2 + topPadding: NOO.factor() / (NOO.isAndroid() ? 2 : 1) + + TcuteButton { + visible: NOO.isAndroid() + width: NOO.factor() * 3 + text: "\u0191" + textColor: enabled ? activPal.highlight : disdPal.text + enabled: currentMelody > -1 + onClicked: showMelody(melView.currentItem) + + font { + pixelSize: NOO.factor() * 2.5 + family: "Nootka" + } + + } + + Item { + width: 1 + height: NOO.factor() * (NOO.isAndroid() ? 0.25 : 1.5) + } + + TcuteButton { + width: NOO.factor() * 3 + text: "+" + textColor: "green" + onClicked: { + loadMelody(); + melView.positionViewAtEnd(); + } + + font { + pixelSize: NOO.factor() * 2.5 + bold: true + } + + } + + Item { + width: 1 + height: NOO.factor() * (NOO.isAndroid() ? 0.25 : 1.5) + } + + TcuteButton { + width: NOO.factor() * 3 + text: "\u2191" + textColor: enabled ? "#008080" : disdPal.text + enabled: currentMelody > 0 + onClicked: { + moveMelody(currentMelody, currentMelody - 1); + currentMelody--; + } + + font { + pixelSize: NOO.factor() * 2.5 + family: "Nootka" + } + + } + + TcuteButton { + width: NOO.factor() * 3 + text: "\u2193" + textColor: enabled ? "#008080" : disdPal.text + enabled: currentMelody > -1 && currentMelody < melMod.count - 1 + onClicked: { + moveMelody(currentMelody, currentMelody + 1); + currentMelody++; + } + + font { + pixelSize: NOO.factor() * 2.5 + family: "Nootka" + } + + } + + Item { + width: 1 + height: NOO.factor() * (NOO.isAndroid() ? 0.25 : 1.5) + } + + TcuteButton { + width: NOO.factor() * 3 + text: "-" + textColor: enabled ? "red" : disdPal.text + enabled: currentMelody > -1 + onClicked: removeWrapper(currentMelody) + + font { + pixelSize: NOO.factor() * 2.5 + bold: true + } + + Shortcut { + enabled: currentMelody > -1 + sequence: "del" + onActivated: removeWrapper(currentMelody) + } + + } + } - } + } - } - - Component { - id: divideComp - TpopupDialog { - width: divMel.width + NOO.factor() * 2 - height: divMel.height + NOO.factor() * 5 - DivideMelody { id: divMel } - onAccepted: { - if (divMel.divisionBy > 0) { - melListView.divideMelody(currWrapp.nr, divMel.divisionBy) - currWrapp.reload() - if (melPreview) { - melPreview.reload() - melPreview.close() - } - creator.melodyListChanged() + + Component { + id: divideComp + + TpopupDialog { + width: divMel.width + NOO.factor() * 2 + height: divMel.height + NOO.factor() * 5 + onAccepted: { + if (divMel.divisionBy > 0) { + melListView.divideMelody(currWrapp.nr, divMel.divisionBy); + currWrapp.reload(); + if (melPreview) { + melPreview.reload(); + melPreview.close(); + } + creator.melodyListChanged(); + } + } + + DivideMelody { + id: divMel + } + } - } + } - } - - Component { - id: transcomp - TpopupDialog { - id: transPop - property alias transpose: transpose - width: transpose.width + NOO.factor() * 2 - height: transpose.height + NOO.factor() * 5 - Transpose { - id: transpose - } - onAboutToShow: transpose.currentKeyId = currWrapp ? currWrapp.wrapper.key + 7 : 7 - onAccepted: { - if (transpose.toKey || transpose.byInterval) { - if (transpose.toKey) - currWrapp.wrapper.key = transpose.selectedKey - melListView.transpose(transpose.outShift, transpose.outScaleToRest, transpose.inInstrumentScale, currWrapp.wrapper) - if (melPreview) { - melPreview.reload() - melPreview.close() - } - creator.melodyListChanged() + + Component { + id: transcomp + + TpopupDialog { + id: transPop + + property alias transpose: transpose + + width: transpose.width + NOO.factor() * 2 + height: transpose.height + NOO.factor() * 5 + onAboutToShow: transpose.currentKeyId = currWrapp ? currWrapp.wrapper.key + 7 : 7 + onAccepted: { + if (transpose.toKey || transpose.byInterval) { + if (transpose.toKey) + currWrapp.wrapper.key = transpose.selectedKey; + + melListView.transpose(transpose.outShift, transpose.outScaleToRest, transpose.inInstrumentScale, currWrapp.wrapper); + if (melPreview) { + melPreview.reload(); + melPreview.close(); + } + creator.melodyListChanged(); + } + } + + Transpose { + id: transpose + } + } - } + } - } - - onAppendMelody: melMod.append({}) - onInsertMelody: melMod.insert(melId, {}) - - onMelodiesChanged: creator.melodyListChanged() - - property var melPreview: null - property var currWrapp: null - property var dividePop: null - property var transPop: null - - function showMelody(wrappId) { - if (!melPreview) { - melPreview = Qt.createComponent("qrc:/score/MelodyPreview.qml").createObject(NOO.isAndroid() ? nootkaWindow : melPage, - { "width": (NOO.isAndroid() ? nootkaWindow.width : melListView.width) - NOO.factor() * 2, - "maxHeight": melPage.height - NOO.factor() * (NOO.isAndroid() ? 4 : 10) - }) - melPreview.wantDivide.connect(showDividePopup) - melPreview.wantTranspose.connect(showTransposePopup) + + melodyModel: ListModel { + id: melMod } - currWrapp = wrappId - melPreview.open() - melPreview.melody = getMelody(wrappId.nr) - melPreview.idText = (wrappId.nr + 1) + "." - melPreview.border.color = wrappId.outOfScale ? "red" : activPal.highlight - } - - function removeWrapper(id) { - melMod.remove(id) - removeMelody(id) - currentMelody = -1 - } - function moveMelody(from, to) { - melMod.move(from, to, 1) - swapMelodies(from, to) - } - function showDividePopup() { - if (!dividePop) - dividePop = divideComp.createObject(melPage) - dividePop.open() - } - function showTransposePopup() { - if (!transPop) - transPop = transcomp.createObject(melPage) - transPop.transpose.initialKey = currWrapp.wrapper.key - transPop.open() - } + } diff --git a/src/qml/level/MelodyPage.qml b/src/qml/level/MelodyPage.qml index 2b5eec1f5b061712d6ea3440ac2f1bb77d7df17e..fbc0b5abd2c1cf6d2005557936220afdd8fef890 100644 --- a/src/qml/level/MelodyPage.qml +++ b/src/qml/level/MelodyPage.qml @@ -2,212 +2,277 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" +import "../score" +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 - -import Nootka 1.0 import Score 1.0 -import "../" -import "../score" - Tflickable { - id: melPage - height: parent.height - contentHeight: melodyCol.height + NOO.factor() * 2 - contentWidth: width - - Column { - id: melodyCol - width: parent.width - enabled: creator.isMelody - - Tile { - id: topTile - width: parent.width * (NOO.isAndroid() ? 0.98 : 1) - readonly property string keyRangeText: "<br>" + qsTr("They will be transposed if key signatures are set to be used and any of them differs from the key(s) defined below.") - property var descList: [ qsTr("Melodies are composed from notes in range defined on the 'Range' page."), - qsTr("Melodies are composed from notes selected on the score below."), - qsTr("Melodies are selected from the list below.") ] - description: descList[melCombo.currentIndex] + (melCombo.currentIndex > 0 ? keyRangeText : "") - Row { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - Text { - text: NOO.TR("LevelCreator", "Melody") - anchors.verticalCenter: parent.verticalCenter - color: enabled ? activPal.text : disdPal.text - } - TcomboBox { - id: melCombo - width: NOO.factor() * 20 - model: [ qsTr("from notes in range"), qsTr("from selected notes"), qsTr("from set of melodies") ] - currentIndex: creator.howGetMelody - onActivated: creator.howGetMelody = currentIndex + id: melPage + + property var melListView: null + + function checkMelodyView() { + if (melCombo.currentIndex === 2) { + if (!melListView) { + var c = Qt.createComponent("qrc:/level/MelodyListView.qml"); + melListView = c.createObject(melodyCol); + melListView.width = Qt.binding(function() { + return melodyCol.width - 10; + }); + } + melListView.setLevel(creator.level()); + melListView.currentMelody = -1; // reset selection + } else if (melListView) { + melListView.destroy(); } - } } - Grid { - id: melGrid - spacing: melPage.width / (NOO.isAndroid() ? 100 : 50) - columns: NOO.factor() * 50 > melPage.width ? 1 : 2 // (melLenTile.visible ? 2 : 1) - anchors.horizontalCenter: parent.horizontalCenter - - Tile { - id: melLenTile - visible: creator.isMelody && !creator.hasRhythms && melCombo.currentIndex !== 2 - description: qsTr("Maximum number of notes in a melody. Melody length is random value between 70% and 100% of that number.") - anchors.horizontalCenter: undefined - width: melGrid.columns === 1 ? melPage.width * 0.98 : Math.max(lenRow.width + NOO.factor() * 4, melPage.width * 0.48) - Row { - id: lenRow - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - Text { - text: qsTr("Melody length") - anchors.verticalCenter: parent.verticalCenter - color: enabled ? activPal.text : disdPal.text - } - TspinBox { - id: lenSpin - from: 1; to: 50 - value: creator.melodyLen - onValueModified: creator.melodyLen = lenSpin.value - } - } - } - EndOnTonicTile { - visible: melCombo.currentIndex !== 2 - width: melGrid.columns === 1 ? melPage.width * 0.98 : Math.max(checkBox.width + NOO.factor() * 4, melPage.width * 0.48) - checked: creator.endsOnTonic - checkBox.onClicked: creator.endsOnTonic = checked - } - - Tile { - width: melGrid.columns === 1 ? melPage.width * 0.98 : Math.max(randOrderChB.width + NOO.factor() * 4, melPage.width * 0.48) - visible: melCombo.currentIndex === 2 - anchors.horizontalCenter: undefined - TcheckBox { - id: randOrderChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("random order") - checked: creator.randomOrder - onClicked: creator.randomOrder = checked - } - description: qsTr("When checked, melodies from the list will be asked in random order.") - } - Tile { - width: melGrid.columns === 1 ? melPage.width * 0.98 : Math.max(repeatRow.width + NOO.factor() * 4, melPage.width * 0.48) - visible: melCombo.currentIndex === 2 - anchors.horizontalCenter: undefined - description: qsTr("How many times during an exam a melody from the list has to be played or written correctly. Warning! It multiplies question number.") - Row { - id: repeatRow - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - Text { - text: qsTr("number of repeats") - anchors.verticalCenter: parent.verticalCenter - color: enabled ? activPal.text : disdPal.text - } - TspinBox { - id: repeatSpin - from: 1; to: 15 - value: creator.repeatsNumber - onValueModified: creator.repeatsNumber = repeatSpin.value - } - } - } + + function updateNotesList() { + listScore.clearScore(); + listScore.clef = creator.clef; + listScore.keySignature = creator.keyOfRandList; + for (var i = 0; i < creator.notesInList(); ++i) listScore.addNote(creator.noteFromList(i)) } - Item { - width: parent.width; height: melPage.height - topTile.height - melGrid.height //- tempoRange.height - visible: melCombo.currentIndex === 1 - Score { - id: listScore - visible: melCombo.currentIndex === 1 - anchors.fill: parent - meter: Tmeter.NoMeter - enableKeySign: creator.useKeySign - scoreObj.allowAdding: visible - scoreObj.editMode: true - } + + function saveLevel() { + if (melCombo.currentIndex === 1) { + // melody from note list + creator.keyOfRandList = listScore.scoreObj.keySignature; + for (var i = 0; i < listScore.notesCount; ++i) creator.setNoteOfList(i, listScore.scoreObj.noteAt(i)) + } // melody from set has melodies aready in the working level } - Tile { - description: qsTr("If selected, tempo in succeeding questions will increase - but only up to value when shortest melody note is possible to play/detect.") - Row { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - TcheckBox { - id: inTempoChB - text: qsTr("Play in tempo") + + height: parent.height + contentHeight: melodyCol.height + NOO.factor() * 2 + contentWidth: width + Component.onCompleted: { + if (listScore.visible) + updateNotesList(); + + checkMelodyView(); + } + + Column { + id: melodyCol + + width: parent.width + enabled: creator.isMelody + + Tile { + id: topTile + + readonly property string keyRangeText: "<br>" + qsTr("They will be transposed if key signatures are set to be used and any of them differs from the key(s) defined below.") + property var descList: [qsTr("Melodies are composed from notes in range defined on the 'Range' page."), qsTr("Melodies are composed from notes selected on the score below."), qsTr("Melodies are selected from the list below.")] + + width: parent.width * (NOO.isAndroid() ? 0.98 : 1) + description: descList[melCombo.currentIndex] + (melCombo.currentIndex > 0 ? keyRangeText : "") + + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + Text { + text: NOO.TR("LevelCreator", "Melody") + anchors.verticalCenter: parent.verticalCenter + color: enabled ? activPal.text : disdPal.text + } + + TcomboBox { + id: melCombo + + width: NOO.factor() * 20 + model: [qsTr("from notes in range"), qsTr("from selected notes"), qsTr("from set of melodies")] + currentIndex: creator.howGetMelody + onActivated: creator.howGetMelody = currentIndex + } + + } + } - Text { - anchors.verticalCenter: parent.verticalCenter - text: Math.floor(tempoRange.first.value); font { bold: true; pixelSize: NOO.factor() * 0.9 } - color: enabled ? activPal.text : disdPal.text + + Grid { + id: melGrid + + spacing: melPage.width / (NOO.isAndroid() ? 100 : 50) + columns: NOO.factor() * 50 > melPage.width ? 1 : 2 // (melLenTile.visible ? 2 : 1) + anchors.horizontalCenter: parent.horizontalCenter + + Tile { + id: melLenTile + + visible: creator.isMelody && !creator.hasRhythms && melCombo.currentIndex !== 2 + description: qsTr("Maximum number of notes in a melody. Melody length is random value between 70% and 100% of that number.") + anchors.horizontalCenter: undefined + width: melGrid.columns === 1 ? melPage.width * 0.98 : Math.max(lenRow.width + NOO.factor() * 4, melPage.width * 0.48) + + Row { + id: lenRow + + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + Text { + text: qsTr("Melody length") + anchors.verticalCenter: parent.verticalCenter + color: enabled ? activPal.text : disdPal.text + } + + TspinBox { + id: lenSpin + + from: 1 + to: 50 + value: creator.melodyLen + onValueModified: creator.melodyLen = lenSpin.value + } + + } + + } + + EndOnTonicTile { + visible: melCombo.currentIndex !== 2 + width: melGrid.columns === 1 ? melPage.width * 0.98 : Math.max(checkBox.width + NOO.factor() * 4, melPage.width * 0.48) + checked: creator.endsOnTonic + checkBox.onClicked: creator.endsOnTonic = checked + } + + Tile { + width: melGrid.columns === 1 ? melPage.width * 0.98 : Math.max(randOrderChB.width + NOO.factor() * 4, melPage.width * 0.48) + visible: melCombo.currentIndex === 2 + anchors.horizontalCenter: undefined + description: qsTr("When checked, melodies from the list will be asked in random order.") + + TcheckBox { + id: randOrderChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("random order") + checked: creator.randomOrder + onClicked: creator.randomOrder = checked + } + + } + + Tile { + width: melGrid.columns === 1 ? melPage.width * 0.98 : Math.max(repeatRow.width + NOO.factor() * 4, melPage.width * 0.48) + visible: melCombo.currentIndex === 2 + anchors.horizontalCenter: undefined + description: qsTr("How many times during an exam a melody from the list has to be played or written correctly. Warning! It multiplies question number.") + + Row { + id: repeatRow + + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + Text { + text: qsTr("number of repeats") + anchors.verticalCenter: parent.verticalCenter + color: enabled ? activPal.text : disdPal.text + } + + TspinBox { + id: repeatSpin + + from: 1 + to: 15 + value: creator.repeatsNumber + onValueModified: creator.repeatsNumber = repeatSpin.value + } + + } + + } + } - TrangeSlider { - id: tempoRange - anchors.verticalCenter: parent.verticalCenter - width: parent.parent.width / 3 - first.value: 60; second.value: 120 - from: 40; to: 180 - stepSize: 5; snapMode: RangeSlider.SnapAlways + + Item { + width: parent.width //- tempoRange.height + height: melPage.height - topTile.height - melGrid.height + visible: melCombo.currentIndex === 1 + + Score { + id: listScore + + visible: melCombo.currentIndex === 1 + anchors.fill: parent + meter: Tmeter.NoMeter + enableKeySign: creator.useKeySign + scoreObj.allowAdding: visible + scoreObj.editMode: true + } + } - Text { - anchors.verticalCenter: parent.verticalCenter - text: Math.floor(tempoRange.second.value); font { bold: true; pixelSize: NOO.factor() * 0.9 } - color: enabled ? activPal.text : disdPal.text + + Tile { + description: qsTr("If selected, tempo in succeeding questions will increase - but only up to value when shortest melody note is possible to play/detect.") + + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + TcheckBox { + id: inTempoChB + + text: qsTr("Play in tempo") + } + + Text { + anchors.verticalCenter: parent.verticalCenter + text: Math.floor(tempoRange.first.value) + color: enabled ? activPal.text : disdPal.text + + font { + bold: true + pixelSize: NOO.factor() * 0.9 + } + + } + + TrangeSlider { + id: tempoRange + + anchors.verticalCenter: parent.verticalCenter + width: parent.parent.width / 3 + first.value: 60 + second.value: 120 + from: 40 + to: 180 + stepSize: 5 + snapMode: RangeSlider.SnapAlways + } + + Text { + anchors.verticalCenter: parent.verticalCenter + text: Math.floor(tempoRange.second.value) + color: enabled ? activPal.text : disdPal.text + + font { + bold: true + pixelSize: NOO.factor() * 0.9 + } + + } + + } + } - } + } - } - - Component.onCompleted: { - if (listScore.visible) - updateNotesList() - checkMelodyView() - } - - Connections { - target: creator - onUpdateNotesList: updateNotesList() - onUpdateMelodyList: checkMelodyView() - } - - property var melListView: null - Connections { - target: melCombo - onCurrentIndexChanged: checkMelodyView() - } - - function checkMelodyView() { - if (melCombo.currentIndex === 2) { - if (!melListView) { - var c = Qt.createComponent("qrc:/level/MelodyListView.qml") - melListView = c.createObject(melodyCol) - melListView.width = Qt.binding(function() { return melodyCol.width - 10 }) - } - melListView.setLevel(creator.level()) - melListView.currentMelody = -1 // reset selection - } else if (melListView) { - melListView.destroy() + + Connections { + target: creator + onUpdateNotesList: updateNotesList() + onUpdateMelodyList: checkMelodyView() + } + + Connections { + target: melCombo + onCurrentIndexChanged: checkMelodyView() } - } - - function updateNotesList() { - listScore.clearScore() - listScore.clef = creator.clef - listScore.keySignature = creator.keyOfRandList - for (var i = 0; i < creator.notesInList(); ++i) - listScore.addNote(creator.noteFromList(i)) - } - - function saveLevel() { - if (melCombo.currentIndex === 1) { // melody from note list - creator.keyOfRandList = listScore.scoreObj.keySignature - for (var i = 0; i < listScore.notesCount; ++i) - creator.setNoteOfList(i, listScore.scoreObj.noteAt(i)) - } // melody from set has melodies aready in the working level - } + } diff --git a/src/qml/level/MelodyWrapper.qml b/src/qml/level/MelodyWrapper.qml index abc6a14ca20bf12d31054d444c60fddd03cc914c..f0c83e33405092263c6466ad49191b1310d132e8 100644 --- a/src/qml/level/MelodyWrapper.qml +++ b/src/qml/level/MelodyWrapper.qml @@ -2,171 +2,309 @@ * 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.Dialogs 1.0 +import QtQuick 2.12 import Score 1.0 -import "../score" -import "../" - MouseArea { - id: wrapArea + id: wrapArea - height: NOO.factor() * 10 + property bool held: false + property alias nr: wrapper.nr + property alias outOfScale: wrapper.outOfScale + property alias wrapper: wrapper - property bool held: false - property alias nr: wrapper.nr - property alias outOfScale: wrapper.outOfScale - property alias wrapper: wrapper + function updateMelody() { + wrapper.updateMelody(); + } - function updateMelody() { wrapper.updateMelody() } - function reload() { wrapper.reload() } + function reload() { + wrapper.reload(); + } - hoverEnabled: false // triggered with delay to avoid highlighting all wrappers - drag.target: wrapArea.held ? wrapper : undefined - drag.axis: Drag.YAxis + height: NOO.factor() * 10 + hoverEnabled: false // triggered with delay to avoid highlighting all wrappers + drag.target: wrapArea.held ? wrapper : undefined + drag.axis: Drag.YAxis + onPressAndHold: wrapArea.held = true + onReleased: wrapArea.held = false + onClicked: melListView.currentMelody = nr + cursorShape: held ? Qt.SizeVerCursor : (containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor) - onPressAndHold: wrapArea.held = true - onReleased: wrapArea.held = false - onClicked: melListView.currentMelody = nr + TmelodyWrapper { + id: wrapper - cursorShape: held ? Qt.SizeVerCursor : (containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor) + score: sc.scoreObj + melodyView: melListView + width: wrapArea.width + height: wrapArea.height + Drag.active: wrapArea.held + Drag.source: wrapArea + Drag.hotSpot.x: width / 2 + Drag.hotSpot.y: height / 2 - TmelodyWrapper { - id: wrapper + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } - score: sc.scoreObj - melodyView: melListView + Score { + id: sc - width: wrapArea.width; height: wrapArea.height + property color base: wrapper.outOfScale ? "red" : activPal.base - Drag.active: wrapArea.held - Drag.source: wrapArea - Drag.hotSpot.x: width / 2 - Drag.hotSpot.y: height / 2 + anchors.fill: parent + interactive: false + readOnly: true + bgColor: Qt.tint(activPal.base, NOO.alpha(wrapArea.held ? activPal.text : (nr === melListView.currentMelody ? activPal.highlight : base), 50)) - anchors { - horizontalCenter: parent.horizontalCenter - verticalCenter: parent.verticalCenter - } + Behavior on bgColor { + enabled: GLOB.useAnimations - states: State { - when: wrapArea.held - ParentChange { target: wrapper; parent: melListView.viewRoot } - AnchorChanges { - target: wrapper - anchors { horizontalCenter: undefined; verticalCenter: undefined } - } - } + ColorAnimation { + duration: 150 + } - Score { - id: sc - property color base: wrapper.outOfScale ? "red" : activPal.base - anchors.fill: parent - interactive: false - readOnly: true - bgColor: Qt.tint(activPal.base, NOO.alpha(wrapArea.held ? activPal.text : (nr === melListView.currentMelody ? activPal.highlight : base), 50)) - Behavior on bgColor { enabled: GLOB.useAnimations; ColorAnimation { duration: 150 } } - } + } - Rectangle { // this is part of covering rectangle - height: parent.height; width: parent.height - rotation: -90; - x: parent.width - scoreCover.width - width - gradient: Gradient { - GradientStop { position: 0.0; color: "transparent" } - GradientStop { position: 0.75; color: sc.bgColor } - } - } - Rectangle { - id: scoreCover - height: parent.height; width: parent.width - parent.height * 4 - anchors { right: parent.right } - color: sc.bgColor - Text { - visible: wrapper.outOfScale - anchors { verticalCenter: parent.verticalCenter; right: parent.right; margins: 10 } - font.pixelSize: parent.height * 0.2 - text: NOO.TR("OutScaleTip", "Out of instrument scale!") - color: "red" - } - Row { - y: parent.height / 3 - anchors { right: parent.right; margins: 10 } - spacing: NOO.factor() / 2 - RectButton { - height: scoreCover.height / 4 - font { family: "Nootka"; pixelSize: scoreCover.height / 4 } - text: "\u2702" - textColor: wrapArea.containsMouse || NOO.isAndroid() ? activPal.text : NOO.alpha(activPal.text, 30) - Behavior on textColor { enabled: GLOB.useAnimations; ColorAnimation {} } - onClicked: { - melListView.currWrapp = wrapArea - melListView.showDividePopup() - } } - RectButton { - height: scoreCover.height / 4 - font { family: "Nootka"; pixelSize: scoreCover.height / 4 } - text: "\u0192" - textColor: wrapArea.containsMouse || NOO.isAndroid() ? activPal.text : NOO.alpha(activPal.text, 30) - Behavior on textColor { enabled: GLOB.useAnimations; ColorAnimation {} } - onClicked: { - melListView.currWrapp = wrapArea - melListView.showTransposePopup() - } + + // this is part of covering rectangle + Rectangle { + height: parent.height + width: parent.height + rotation: -90 + x: parent.width - scoreCover.width - width + + gradient: Gradient { + GradientStop { + position: 0 + color: "transparent" + } + + GradientStop { + position: 0.75 + color: sc.bgColor + } + + } + } - } - RectButton { - visible: !NOO.isAndroid() - anchors { bottom: parent.bottom; right: parent.right; margins: 10 } - height: parent.height / 3 - font { family: "Nootka"; pixelSize: parent.height / 3 } - text: "\u0191" - textColor: wrapArea.containsMouse || NOO.isAndroid() ? activPal.text : NOO.alpha(activPal.text, 30) - Behavior on textColor { enabled: GLOB.useAnimations; ColorAnimation {} } - onClicked: melListView.showMelody(wrapArea) - } - } - Text { - x: NOO.factor() / 2; y: NOO.factor() / 2 - font { bold: true } - text: nr + 1; color: NOO.alpha(activPal.text, 150) - } + Rectangle { + id: scoreCover - Text { - text: wrapper.title - x: (parent.width - width) / 2 - y: NOO.factor() / 4 - font { bold: true; pixelSize: NOO.factor() * 1.3 } - minimumPixelSize: NOO.factor() * 0.9; fontSizeMode: Text.HorizontalFit - color: wrapArea.containsMouse ? activPal.text : NOO.alpha(activPal.text, 150) - width: Math.min(NOO.factor() * 25, parent.width - NOO.factor() * 6); elide: Text.ElideRight - horizontalAlignment: Text.AlignHCenter - Behavior on color { enabled: GLOB.useAnimations; ColorAnimation {} } - } + height: parent.height + width: parent.width - parent.height * 4 + color: sc.bgColor + + anchors { + right: parent.right + } + + Text { + visible: wrapper.outOfScale + font.pixelSize: parent.height * 0.2 + text: NOO.TR("OutScaleTip", "Out of instrument scale!") + color: "red" + + anchors { + verticalCenter: parent.verticalCenter + right: parent.right + margins: 10 + } + + } + + Row { + y: parent.height / 3 + spacing: NOO.factor() / 2 + + anchors { + right: parent.right + margins: 10 + } + + RectButton { + height: scoreCover.height / 4 + text: "\u2702" + textColor: wrapArea.containsMouse || NOO.isAndroid() ? activPal.text : NOO.alpha(activPal.text, 30) + onClicked: { + melListView.currWrapp = wrapArea; + melListView.showDividePopup(); + } + + font { + family: "Nootka" + pixelSize: scoreCover.height / 4 + } + + Behavior on textColor { + enabled: GLOB.useAnimations + + ColorAnimation { + } + + } + + } + + RectButton { + height: scoreCover.height / 4 + text: "\u0192" + textColor: wrapArea.containsMouse || NOO.isAndroid() ? activPal.text : NOO.alpha(activPal.text, 30) + onClicked: { + melListView.currWrapp = wrapArea; + melListView.showTransposePopup(); + } + + font { + family: "Nootka" + pixelSize: scoreCover.height / 4 + } + + Behavior on textColor { + enabled: GLOB.useAnimations + + ColorAnimation { + } + + } + + } + + } + + RectButton { + visible: !NOO.isAndroid() + height: parent.height / 3 + text: "\u0191" + textColor: wrapArea.containsMouse || NOO.isAndroid() ? activPal.text : NOO.alpha(activPal.text, 30) + onClicked: melListView.showMelody(wrapArea) + + anchors { + bottom: parent.bottom + right: parent.right + margins: 10 + } + + font { + family: "Nootka" + pixelSize: parent.height / 3 + } + + Behavior on textColor { + enabled: GLOB.useAnimations + + ColorAnimation { + } + + } + + } + + } + + Text { + x: NOO.factor() / 2 + y: NOO.factor() / 2 + text: nr + 1 + color: NOO.alpha(activPal.text, 150) + + font { + bold: true + } + + } + + Text { + text: wrapper.title + x: (parent.width - width) / 2 + y: NOO.factor() / 4 + minimumPixelSize: NOO.factor() * 0.9 + fontSizeMode: Text.HorizontalFit + color: wrapArea.containsMouse ? activPal.text : NOO.alpha(activPal.text, 150) + width: Math.min(NOO.factor() * 25, parent.width - NOO.factor() * 6) + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + + font { + bold: true + pixelSize: NOO.factor() * 1.3 + } + + Behavior on color { + enabled: GLOB.useAnimations + + ColorAnimation { + } + + } + + } + + Text { + text: wrapper.composer + y: NOO.factor() * 1.5 + color: wrapArea.containsMouse ? activPal.text : NOO.alpha(activPal.text, 150) + maximumLineCount: 1 + + anchors { + right: parent.right + rightMargin: NOO.factor() / 4 + } + + Behavior on color { + enabled: GLOB.useAnimations + + ColorAnimation { + } + + } + + } + // TmelodyWrapper + + states: State { + when: wrapArea.held + + ParentChange { + target: wrapper + parent: melListView.viewRoot + } + + AnchorChanges { + target: wrapper + + anchors { + horizontalCenter: undefined + verticalCenter: undefined + } + + } + + } - Text { - text: wrapper.composer - anchors { right: parent.right; rightMargin: NOO.factor() / 4 } - y: NOO.factor() * 1.5 - color: wrapArea.containsMouse ? activPal.text : NOO.alpha(activPal.text, 150) - maximumLineCount: 1 - Behavior on color { enabled: GLOB.useAnimations; ColorAnimation {} } } - } // TmelodyWrapper - - DropArea { - anchors { fill: parent; margins: 10 } - onEntered: { - if (drag.source.nr !== wrapArea.nr) { - if (drag.source.nr === melListView.currentMelody) - melListView.currentMelody = wrapper.nr - melListView.moveMelody(drag.source.nr, wrapArea.nr) - } + + DropArea { + onEntered: { + if (drag.source.nr !== wrapArea.nr) { + if (drag.source.nr === melListView.currentMelody) + melListView.currentMelody = wrapper.nr; + + melListView.moveMelody(drag.source.nr, wrapArea.nr); + } + } + + anchors { + fill: parent + margins: 10 + } + } - } + } diff --git a/src/qml/level/MeterSelector.qml b/src/qml/level/MeterSelector.qml index 7d257b2293c1b036e4130b9d25859adc724296da..7031112a76989ef322eb2270357491a3dceb6046 100644 --- a/src/qml/level/MeterSelector.qml +++ b/src/qml/level/MeterSelector.qml @@ -2,56 +2,75 @@ * 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 QtQuick.Controls 2.12 -import Nootka 1.0 -import "../" - ListView { - id: meterList - - property int meters: 0 - - signal metersModified() - - clip: true - width: model * (NOO.factor() * 4.5) - contentWidth: model * (NOO.factor() * 4.25) - height: NOO.factor() * 3 - orientation: ListView.Horizontal - spacing: NOO.factor() / 4 - - ScrollBar.horizontal: ScrollBar { active: enabled; visible: active } - - model: 12 - delegate: Component { - Rectangle { - width: NOO.factor() * 5; height: NOO.factor() * 3 - color: enabled ? (index % 2 ? activPal.alternateBase : activPal.base) : Qt.darker(disdPal.window, 1.2) - property int mask: Math.pow(2, index) - TcheckBox { - width: NOO.factor() * 5 - x: -y; y: NOO.factor() * 0.2 - checked: meters & mask - onClicked: { - if (checked) - meters |= mask - else - meters &= ~mask - metersModified() - } - contentItem: Item { - height: NOO.factor() * 2; width: NOO.factor() * 2 - Text { - y: NOO.factor() * -3 - text: NOO.meter(Math.pow(2, index)).symbol() - leftPadding: NOO.factor() * 2.5 - color: enabled ? activPal.text : disdPal.text - font { family: "Scorek"; pixelSize: NOO.factor() * 2.2 } - } + id: meterList + + property int meters: 0 + + signal metersModified() + + clip: true + width: model * (NOO.factor() * 4.5) + contentWidth: model * (NOO.factor() * 4.25) + height: NOO.factor() * 3 + orientation: ListView.Horizontal + spacing: NOO.factor() / 4 + model: 12 + + ScrollBar.horizontal: ScrollBar { + active: enabled + visible: active + } + + delegate: Component { + Rectangle { + property int mask: Math.pow(2, index) + + width: NOO.factor() * 5 + height: NOO.factor() * 3 + color: enabled ? (index % 2 ? activPal.alternateBase : activPal.base) : Qt.darker(disdPal.window, 1.2) + + TcheckBox { + width: NOO.factor() * 5 + x: -y + y: NOO.factor() * 0.2 + checked: meters & mask + onClicked: { + if (checked) + meters |= mask; + else + meters &= ~mask; + metersModified(); + } + + contentItem: Item { + height: NOO.factor() * 2 + width: NOO.factor() * 2 + + Text { + y: NOO.factor() * -3 + text: NOO.meter(Math.pow(2, index)).symbol() + leftPadding: NOO.factor() * 2.5 + color: enabled ? activPal.text : disdPal.text + + font { + family: "Scorek" + pixelSize: NOO.factor() * 2.2 + } + + } + + } + + } + } - } + } - } + } diff --git a/src/qml/level/NewerVersionPopup.qml b/src/qml/level/NewerVersionPopup.qml index 2dab4d9e02fec707b3b49b3b07f01fe73f291ab3..bfcf4176a06949ee556a57d8b21ca075b5cc9047 100644 --- a/src/qml/level/NewerVersionPopup.qml +++ b/src/qml/level/NewerVersionPopup.qml @@ -2,39 +2,50 @@ * 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 Nootka 1.0 import "../" +import Nootka 1.0 +import QtQuick 2.12 TpopupDialog { - id: warnPopup + id: warnPopup + + property string fName: "" + + caption: NOO.TR("dummy", "Update Nootka") + visible: true + modal: true + width: warnCol.width + NOO.factor() * 2 + height: warnCol.height + NOO.factor() * 7 + acceptButton.text: NOO.TR("GotIt", "GOT IT!") + rejectButton.visible: false + bgColor: Qt.tint(activPal.base, NOO.alpha("green", 20)) + glowRect.radius: NOO.factor() * 2 + onClosed: destroy() + + border { + color: "red" + width: NOO.factor() / 4 + } - property string fName: "" + Column { + id: warnCol - caption: NOO.TR("dummy", "Update Nootka") + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 - visible: true; modal: true - width: warnCol.width + NOO.factor() * 2; height: warnCol.height + NOO.factor() * 7 + Text { + color: activPal.text + lineHeight: 1.25 + horizontalAlignment: Text.AlignHCenter + text: NOO.TR("dummy", "File:<br><font color=\"red\"> %1</font><br>was created with newer Nootka version.<br>To open it you have to update Nootka.").arg(fName) - acceptButton.text: NOO.TR("GotIt", "GOT IT!") - rejectButton.visible: false + font { + pixelSize: NOO.factor() * 1.5 + bold: true + } - bgColor: Qt.tint(activPal.base, NOO.alpha("green", 20)) - border { color: "red"; width: NOO.factor() / 4.0 } - glowRect.radius: NOO.factor() * 2 + } - Column { - id: warnCol - x: (parent.width - width) / 2; y: (parent.height - height) / 2; - Text { - color: activPal.text - font { pixelSize: NOO.factor() * 1.5; bold: true } - lineHeight: 1.25 - horizontalAlignment: Text.AlignHCenter - text: NOO.TR("dummy", "File:<br><font color=\"red\"> %1</font><br>was created with newer Nootka version.<br>To open it you have to update Nootka.").arg(fName) } - } - onClosed: destroy() } diff --git a/src/qml/level/PreviewItem.qml b/src/qml/level/PreviewItem.qml index 66e6553f24814f601b2bb2468e41419becee3d7f..21f2ac7207eac825801aae2e2c97e49dccf4c8b2 100644 --- a/src/qml/level/PreviewItem.qml +++ b/src/qml/level/PreviewItem.qml @@ -2,64 +2,70 @@ * Copyright (C) 2020-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 +import QtQuick 2.12 Rectangle { - property int index: aboveItem ? aboveItem.index + (aboveItem.visible ? 1 : 0) : 0 - property var aboveItem: null - property bool layHorizontal: true /** layout direction, horizontal by default */ - property bool handleWidth: false /** When width is maximum value of all similar items */ - property alias text: txt.text /** label */ - property alias text2: txt2.text // value - property alias textItem: txt - property alias textItem2: txt2 - property alias showBottomLine: bottomLine.visible + property int index: aboveItem ? aboveItem.index + (aboveItem.visible ? 1 : 0) : 0 + property var aboveItem: null + property bool layHorizontal: true //* layout direction, horizontal by default + property bool handleWidth: false //* When width is maximum value of all similar items + property alias text: txt.text //* label + property alias text2: txt2.text // value + property alias textItem: txt + property alias textItem2: txt2 + property alias showBottomLine: bottomLine.visible - anchors.horizontalCenter: parent.horizontalCenter + anchors.horizontalCenter: parent.horizontalCenter + implicitWidth: Math.max(layHorizontal ? txt.width + txt2.width : Math.max(txt.width, txt2.width)) + NOO.factor() * 2 + implicitHeight: (layHorizontal ? Math.max(txt.height, txt2.height) : txt.height + txt2.height) + NOO.factor() / 2 + color: index ? NOO.alpha(index % 2 === 1 ? activPal.alternateBase : activPal.base, 150) : "transparent" + visible: text2 !== "" + width: handleWidth ? maxLabelWidth + maxValueWidth + NOO.factor() * 2 : undefined + onImplicitWidthChanged: { + if (handleWidth) { + maxLabelWidth = Math.max(maxLabelWidth, txt.implicitWidth + NOO.factor()); + maxValueWidth = Math.max(maxValueWidth, txt2.implicitWidth + NOO.factor()); + } + } - implicitWidth: Math.max(layHorizontal ? txt.width + txt2.width : Math.max(txt.width, txt2.width)) + NOO.factor() * 2 - implicitHeight: (layHorizontal ? Math.max(txt.height, txt2.height) : txt.height + txt2.height) + NOO.factor() / 2 - color: index ? NOO.alpha(index % 2 === 1 ? activPal.alternateBase : activPal.base, 150) : "transparent" - visible: text2 !== "" - width: handleWidth ? maxLabelWidth + maxValueWidth + NOO.factor() * 2 : undefined + Text { + id: txt - onImplicitWidthChanged: { - if (handleWidth) { - maxLabelWidth = Math.max(maxLabelWidth, txt.implicitWidth + NOO.factor()) - maxValueWidth = Math.max(maxValueWidth, txt2.implicitWidth + NOO.factor()) + x: NOO.factor() + y: layHorizontal ? (parent.height - height) / 2 : 0 + textFormat: Text.StyledText + color: activPal.text + font.pixelSize: NOO.factor() } - } - Text { - id: txt - x: NOO.factor(); y: layHorizontal ? (parent.height - height) / 2 : 0 - textFormat: Text.StyledText - color: activPal.text - font.pixelSize: NOO.factor() - } - Text { - id: txt2 - x: handleWidth ? maxLabelWidth + NOO.factor() + (maxValueWidth - width) / 2 : (layHorizontal ? 0 : (parent.width - width) / 2) - y: (parent.height - height) / 2 - horizontalAlignment: handleWidth ? Text.AlignHCenter : undefined - textFormat: Text.StyledText - color: activPal.text - font.pixelSize: NOO.factor() - } + Text { + id: txt2 + + x: handleWidth ? maxLabelWidth + NOO.factor() + (maxValueWidth - width) / 2 : (layHorizontal ? 0 : (parent.width - width) / 2) + y: (parent.height - height) / 2 + horizontalAlignment: handleWidth ? Text.AlignHCenter : undefined + textFormat: Text.StyledText + color: activPal.text + font.pixelSize: NOO.factor() + } + + Rectangle { + visible: handleWidth + color: activPal.text + width: NOO.factor() / 12 + height: parent.height + x: maxLabelWidth + NOO.factor() * 0.5 + } + + Rectangle { + id: bottomLine + + visible: handleWidth + color: activPal.text + height: NOO.factor() / 12 + width: parent.width + y: parent.height - height / 2 + } - Rectangle { - visible: handleWidth; color: activPal.text - width: NOO.factor() / 12; - height: parent.height - x: maxLabelWidth + NOO.factor() * 0.5 - } - Rectangle { - id: bottomLine - visible: handleWidth; color: activPal.text - height: NOO.factor() / 12; - width: parent.width - y: parent.height - height / 2 - } } diff --git a/src/qml/level/QuestionsBox.qml b/src/qml/level/QuestionsBox.qml index e84ac3fcf64c1a52d6e991a1220b927659bd6b04..4aced673d9752a89e84b3cc1ac06215425ddd60c 100644 --- a/src/qml/level/QuestionsBox.qml +++ b/src/qml/level/QuestionsBox.qml @@ -2,88 +2,130 @@ * 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 Nootka 1.0 -import "../" +Tile { + // anchors.horizontalCenter: undefined + property int qId: 0 + property alias questionText: questionChB.text + property alias questionChecked: questionChB.checked + property int answerBits: 0 + property var answSymb: ["s", "c", GLOB.instrument.glyph, "n"] -Tile { - property int qId: 0 - property alias questionText: questionChB.text - property alias questionChecked: questionChB.checked - property int answerBits: 0 - - property var answSymb: [ "s", "c", GLOB.instrument.glyph, "n" ] - - width: col.width + NOO.factor() * 3 -// anchors.horizontalCenter: undefined - - description: unfold.checked ? qsTr("Select the type of answers for this kind of question.") : "" - - Column { - id: col - anchors.horizontalCenter: parent.horizontalCenter - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() / 2 - TcheckBox { - id: questionChB - anchors.verticalCenter: parent.verticalCenter - onClicked: creator.questionAs = checked ? creator.questionAs | Math.pow(2, qId) : creator.questionAs & ~Math.pow(2, qId) - } - Text { - text: answSymb[qId] + "?" - anchors.verticalCenter: parent.verticalCenter - font { family: "nootka"; pixelSize: NOO.factor() * 2.5 } - color: activPal.text - } - Text { - property bool checked: false - id: unfold - anchors.verticalCenter: parent.verticalCenter - font { pixelSize: NOO.factor() * 2; bold: true } - color: ma.containsMouse ? activPal.highlight : activPal.text - text: " ⋮" - MouseArea { - id: ma - hoverEnabled: true - anchors.fill: parent - onClicked: unfold.checked = !unfold.checked - } - } - } - Row { - spacing: NOO.factor() / 2 - anchors.horizontalCenter: parent.horizontalCenter - Text { text: qsTr("answers") + ":"; anchors.verticalCenter: parent.verticalCenter; color: activPal.text } - Grid { - spacing: NOO.factor() / 2 - columns: unfold.checked ? 1 : 4 - Repeater { - model: 4 - Row { - visible: (index !== 2 || qId !== 2) || GLOB.instrument.isGuitar - property alias checked: aChB.checked - layoutDirection: unfold.checked ? Qt.RightToLeft : Qt.LeftToRight + width: col.width + NOO.factor() * 3 + description: unfold.checked ? qsTr("Select the type of answers for this kind of question.") : "" + + Column { + id: col + + anchors.horizontalCenter: parent.horizontalCenter + + Row { + anchors.horizontalCenter: parent.horizontalCenter spacing: NOO.factor() / 2 + TcheckBox { - id: aChB - text: unfold.checked ? NOO.qaTypeText(index) : "" - checked: answerBits & Math.pow(2, index) - onClicked: creator.setAnswers(qId, checked ? answerBits | Math.pow(2, index) : answerBits & ~Math.pow(2, index)) + id: questionChB + + anchors.verticalCenter: parent.verticalCenter + onClicked: creator.questionAs = checked ? creator.questionAs | Math.pow(2, qId) : creator.questionAs & ~Math.pow(2, qId) + } + + Text { + text: answSymb[qId] + "?" + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + + font { + family: "nootka" + pixelSize: NOO.factor() * 2.5 + } + + } + + Text { + id: unfold + + property bool checked: false + + anchors.verticalCenter: parent.verticalCenter + color: ma.containsMouse ? activPal.highlight : activPal.text + text: " ⋮" + + font { + pixelSize: NOO.factor() * 2 + bold: true + } + + MouseArea { + id: ma + + hoverEnabled: true + anchors.fill: parent + onClicked: unfold.checked = !unfold.checked + } + } + + } + + Row { + spacing: NOO.factor() / 2 + anchors.horizontalCenter: parent.horizontalCenter + Text { - font { family: "nootka"; pixelSize: NOO.factor() * 2.5 } - text: answSymb[index] - width: unfold.checked ? NOO.factor() * 3 : undefined - horizontalAlignment: Text.AlignHCenter - color: activPal.text + text: qsTr("answers") + ":" + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + } + + Grid { + spacing: NOO.factor() / 2 + columns: unfold.checked ? 1 : 4 + + Repeater { + model: 4 + + Row { + property alias checked: aChB.checked + + visible: (index !== 2 || qId !== 2) || GLOB.instrument.isGuitar + layoutDirection: unfold.checked ? Qt.RightToLeft : Qt.LeftToRight + spacing: NOO.factor() / 2 + + TcheckBox { + id: aChB + + text: unfold.checked ? NOO.qaTypeText(index) : "" + checked: answerBits & Math.pow(2, index) + onClicked: creator.setAnswers(qId, checked ? answerBits | Math.pow(2, index) : answerBits & ~Math.pow(2, index)) + } + + Text { + text: answSymb[index] + width: unfold.checked ? NOO.factor() * 3 : undefined + horizontalAlignment: Text.AlignHCenter + color: activPal.text + + font { + family: "nootka" + pixelSize: NOO.factor() * 2.5 + } + + } + + } + + } + } - } + } - } + } - } + } diff --git a/src/qml/level/QuestionsPage.qml b/src/qml/level/QuestionsPage.qml index 099a64989854d6fc3f416c3875d2096450257c97..ebf3061e545f3176222d6db3005072ea42735c0a 100644 --- a/src/qml/level/QuestionsPage.qml +++ b/src/qml/level/QuestionsPage.qml @@ -2,199 +2,274 @@ * 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 Nootka 1.0 -import "../" +Tflickable { + id: qPage + property real spacing: width / 100 + property real padding: width / 200 + // private + property real maxWidth: 0 -Tflickable { - id: qPage - height: parent.height - contentHeight: questionCol.height + NOO.factor() * 2 - contentWidth: width - - property real spacing: width / 100 - property real padding: width / 200 - - // private - property real maxWidth: 0 - - Column { - topPadding: qPage.padding - width: parent.width - id: questionCol - - Tframe { - width: parent.width * 0.99 - anchors.horizontalCenter: parent.horizontalCenter - bgColor: NOO.alpha(creator.isMelody ? NOO.invert(activPal.highlight) : activPal.highlight, 75) - Column { + height: parent.height + contentHeight: questionCol.height + NOO.factor() * 2 + contentWidth: width + + Column { + id: questionCol + + topPadding: qPage.padding width: parent.width - Tile { - Row { - spacing: qPage.width / 50 + + Tframe { + width: parent.width * 0.99 anchors.horizontalCenter: parent.horizontalCenter - Text { - font { family: "Nootka"; pixelSize: NOO.factor() * 3 } - color: activPal.highlight; text: "n" - anchors.verticalCenter: parent.verticalCenter - } - TradioButton { - text: qsTr("single note") - checked: !creator.isMelody - onClicked: creator.isMelody = !checked - anchors.verticalCenter: parent.verticalCenter - } - Rectangle { color: activPal.dimText; width: parent.height / 12; height: parent.height * 0.9; anchors.verticalCenter: parent.verticalCenter } - TradioButton { - text: qsTr("melodies") - checked: creator.isMelody - onClicked: creator.isMelody = checked - anchors.verticalCenter: parent.verticalCenter - } - Text { - font { family: "Nootka"; pixelSize: NOO.factor() * 3 } - color: NOO.invert(activPal.highlight); text: "m" - anchors.verticalCenter: parent.verticalCenter + bgColor: NOO.alpha(creator.isMelody ? NOO.invert(activPal.highlight) : activPal.highlight, 75) + + Column { + width: parent.width + + Tile { + Row { + spacing: qPage.width / 50 + anchors.horizontalCenter: parent.horizontalCenter + + Text { + color: activPal.highlight + text: "n" + anchors.verticalCenter: parent.verticalCenter + + font { + family: "Nootka" + pixelSize: NOO.factor() * 3 + } + + } + + TradioButton { + text: qsTr("single note") + checked: !creator.isMelody + onClicked: creator.isMelody = !checked + anchors.verticalCenter: parent.verticalCenter + } + + Rectangle { + color: activPal.dimText + width: parent.height / 12 + height: parent.height * 0.9 + anchors.verticalCenter: parent.verticalCenter + } + + TradioButton { + text: qsTr("melodies") + checked: creator.isMelody + onClicked: creator.isMelody = checked + anchors.verticalCenter: parent.verticalCenter + } + + Text { + color: NOO.invert(activPal.highlight) + text: "m" + anchors.verticalCenter: parent.verticalCenter + + font { + family: "Nootka" + pixelSize: NOO.factor() * 3 + } + + } + + } + + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + font.bold: true + color: activPal.text + text: qsTr("Kind of questions and answers" + ":") + } + // single note + + Flow { + width: parent.width + spacing: qPage.spacing + padding: qPage.padding + visible: !creator.isMelody + + Repeater { + id: questRep + + model: 4 + + Item { + width: maxWidth + height: qBox.height + + QuestionsBox { + id: qBox + + qId: index + visible: index != 2 || GLOB.instrument.type !== 0 + questionText: qsTr("Question") + " " + NOO.qaTypeText(index) + questionChecked: creator.questionAs & Math.pow(2, index) + answerBits: creator.answersAs[index] + Component.onCompleted: maxWidth = Math.max(maxWidth, qBox.width) + } + + } + + } + + } + // melodies + + Grid { + anchors.horizontalCenter: parent.horizontalCenter + spacing: qPage.spacing + padding: qPage.padding + columns: playTile.width + writeTile.width + repeatTile.width + spacing * 3 < qPage.width ? 3 : (playTile.width + writeTile.width + spacing * 2 < qPage.width ? 2 : 1) + visible: creator.isMelody + + Tile { + id: playTile + + anchors.horizontalCenter: undefined + width: Math.max(playChB.width + NOO.factor() * 4, qPage.width * 0.3) + description: NOO.TR("Texam", "Play a melody written in a score") + + TcheckBox { + id: playChB + + anchors.horizontalCenter: parent.horizontalCenter + text: NOO.TR("Texam", "play melody") + checked: creator.playMelody + onClicked: creator.playMelody = checked + } + + } + + Tile { + id: writeTile + + anchors.horizontalCenter: undefined + width: Math.max(writeChB.width + NOO.factor() * 4, qPage.width * 0.3) + description: NOO.TR("Texam", "Listen to a melody and write it on a score") + + TcheckBox { + id: writeChB + + anchors.horizontalCenter: parent.horizontalCenter + text: NOO.TR("Texam", "write melody") + checked: creator.writeMelody + onClicked: creator.writeMelody = checked + } + + } + + Tile { + id: repeatTile + + visible: false // TODO in some next release + anchors.horizontalCenter: undefined + width: Math.max(repeatChB.width + NOO.factor() * 4, qPage.width * 0.3) + description: qsTranslate("Texam", "Listen to a melody and repeat it on your instrument") + + TcheckBox { + id: repeatChB + + enabled: false + anchors.horizontalCenter: parent.horizontalCenter + text: qsTranslate("Texam", "repeat melody") + checked: creator.repeatMelody + onClicked: creator.repeatMelody = checked + } + + } + + } + } - } - } - Text { - anchors.horizontalCenter: parent.horizontalCenter - font.bold: true; color: activPal.text - text: qsTr("Kind of questions and answers" + ":") + } - Flow { // single note - width: parent.width - spacing: qPage.spacing - padding: qPage.padding - visible: !creator.isMelody - Repeater { - id: questRep - model: 4 - Item { - width: maxWidth; height: qBox.height - QuestionsBox { - id: qBox - qId: index - visible: index != 2 || GLOB.instrument.type !== 0 - questionText: qsTr("Question") + " " + NOO.qaTypeText(index) - questionChecked: creator.questionAs & Math.pow(2, index) - answerBits: creator.answersAs[index] - Component.onCompleted: maxWidth = Math.max(maxWidth, qBox.width) - } + + Flow { + width: parent.width + spacing: qPage.spacing + padding: qPage.padding + + Tile { + anchors.horizontalCenter: undefined + width: Math.max(octaveChB.width + NOO.factor() * 2, qPage.width * 0.45) + description: qsTr("if checked, selecting of valid octave is required") + + TcheckBox { + id: octaveChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("require octave") + checked: creator.requireOctave + onClicked: creator.requireOctave = checked + } + } - } - } - Grid { // melodies - anchors.horizontalCenter: parent.horizontalCenter - spacing: qPage.spacing - padding: qPage.padding - columns: playTile.width + writeTile.width + repeatTile.width + spacing * 3 < qPage.width ? 3 : - (playTile.width + writeTile.width + spacing * 2 < qPage.width ? 2 : 1) - visible: creator.isMelody - Tile { - id: playTile - anchors.horizontalCenter: undefined - width: Math.max(playChB.width + NOO.factor() * 4, qPage.width * 0.3) - description: NOO.TR("Texam", "Play a melody written in a score") - TcheckBox { - id: playChB - anchors.horizontalCenter: parent.horizontalCenter - text: NOO.TR("Texam", "play melody") - checked: creator.playMelody - onClicked: creator.playMelody = checked + + Tile { + anchors.horizontalCenter: undefined + width: Math.max(styleChB.width + NOO.factor() * 2, qPage.width * 0.45) + description: qsTr("if checked, note names are switched between letters and solfege.") + + TcheckBox { + id: styleChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("use different naming styles") + checked: creator.requireStyle + onClicked: creator.requireStyle = checked + } + } - } - Tile { - id: writeTile - anchors.horizontalCenter: undefined - width: Math.max(writeChB.width + NOO.factor() * 4, qPage.width * 0.3) - description: NOO.TR("Texam", "Listen to a melody and write it on a score") - TcheckBox { - id: writeChB - anchors.horizontalCenter: parent.horizontalCenter - text: NOO.TR("Texam", "write melody") - checked: creator.writeMelody - onClicked: creator.writeMelody = checked + + Tile { + anchors.horizontalCenter: undefined + visible: GLOB.instrument.isGuitar + width: Math.max(strChB.width + NOO.factor() * 2, qPage.width * 0.45) + description: qsTr("Shows on which string an answer has to be given. Be careful, sometimes it is needed and sometimes it makes no sense.") + + TcheckBox { + id: strChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("show string number in questions") + checked: creator.showStrNr + onClicked: creator.showStrNr = checked + } + } - } - Tile { - id: repeatTile - visible: false // TODO in some next release - anchors.horizontalCenter: undefined - width: Math.max(repeatChB.width + NOO.factor() * 4, qPage.width * 0.3) - description: qsTranslate("Texam", "Listen to a melody and repeat it on your instrument") - TcheckBox { - id: repeatChB - enabled: false - anchors.horizontalCenter: parent.horizontalCenter - text: qsTranslate("Texam", "repeat melody") - checked: creator.repeatMelody - onClicked: creator.repeatMelody = checked + + Tile { + anchors.horizontalCenter: undefined + visible: GLOB.instrument.isGuitar + width: Math.max(lowPosChB.width + NOO.factor() * 2, qPage.width * 0.45) + description: qsTr("if checked, the lowest position in selected fret range is required, otherwise all possible positions of the note are acceptable. To use this, all strings have to be available!") + + TcheckBox { + id: lowPosChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("notes in the lowest position only") + checked: creator.onlyLowPos + onClicked: creator.onlyLowPos = checked + } + } - } - } - } - } - Flow { - width: parent.width - spacing: qPage.spacing - padding: qPage.padding - Tile { - anchors.horizontalCenter: undefined - width: Math.max(octaveChB.width + NOO.factor() * 2, qPage.width * 0.45) - TcheckBox { - id: octaveChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("require octave") - checked: creator.requireOctave - onClicked: creator.requireOctave = checked } - description: qsTr("if checked, selecting of valid octave is required") - } - Tile { - anchors.horizontalCenter: undefined - width: Math.max(styleChB.width + NOO.factor() * 2, qPage.width * 0.45) - TcheckBox { - id: styleChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("use different naming styles") - checked: creator.requireStyle - onClicked: creator.requireStyle = checked - } - description: qsTr("if checked, note names are switched between letters and solfege.") - } - Tile { - anchors.horizontalCenter: undefined - visible: GLOB.instrument.isGuitar - width: Math.max(strChB.width + NOO.factor() * 2, qPage.width * 0.45) - TcheckBox { - id: strChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("show string number in questions") - checked: creator.showStrNr - onClicked: creator.showStrNr = checked - } - description: qsTr("Shows on which string an answer has to be given. Be careful, sometimes it is needed and sometimes it makes no sense.") - } - Tile { - anchors.horizontalCenter: undefined - visible: GLOB.instrument.isGuitar - width: Math.max(lowPosChB.width + NOO.factor() * 2, qPage.width * 0.45) - TcheckBox { - id: lowPosChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("notes in the lowest position only") - checked: creator.onlyLowPos - onClicked: creator.onlyLowPos = checked - } - description: qsTr("if checked, the lowest position in selected fret range is required, otherwise all possible positions of the note are acceptable. To use this, all strings have to be available!") - } + } - } } diff --git a/src/qml/level/RangePage.qml b/src/qml/level/RangePage.qml index 07aa627a682df1564ae52c1c6a862848679a6c84..83a0023e3bdbff4ff59c531aac7ef193897ce3dd 100644 --- a/src/qml/level/RangePage.qml +++ b/src/qml/level/RangePage.qml @@ -2,153 +2,229 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" +import "../score" +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 - -import Nootka 1.0 import Score 1.0 -import "../" -import "../score" - Tflickable { - height: parent.height - contentHeight: rangeGrid.height + NOO.factor() * 2 - contentWidth: Math.max(width, NOO.factor() * 35) - - Connections { - target: creator - onUpdateLevel: { - rangeScore.setNote(0, creator.loNote) - rangeScore.setNote(1, creator.hiNote) + height: parent.height + contentHeight: rangeGrid.height + NOO.factor() * 2 + contentWidth: Math.max(width, NOO.factor() * 35) + + Connections { + target: creator + onUpdateLevel: { + rangeScore.setNote(0, creator.loNote); + rangeScore.setNote(1, creator.hiNote); + } } - } - - Grid { - id: rangeGrid - columns: parent.width > NOO.factor() * 50 && GLOB.instrument.isGuitar? 2 : 1 - width: parent.width - spacing: NOO.factor() / 4 - horizontalItemAlignment: Grid.AlignHCenter - topPadding: NOO.factor() - - Tframe { - width: rangeGrid.columns === 1 ? parent.width * 0.98 : parent.width * 0.49 - Column { - width: parent.width - spacing: NOO.factor() / 2 - Text { text: qsTr("note range:"); color: activPal.text; anchors.horizontalCenter: parent.horizontalCenter } - Item { - height: NOO.factor() * 20 - width: NOO.factor() * 12 - anchors.horizontalCenter: parent.horizontalCenter - Score { - id: rangeScore - anchors.fill: parent - scale: height / firstStaff.linesCount - scoreObj.editMode: true - meter: Tmeter.NoMeter - clef: creator.clef - Component.onCompleted: { - rangeScore.addNote(creator.loNote) - rangeScore.addNote(creator.hiNote) - } - Connections { - target: rangeScore.firstStaff.clef - onClicked: creator.clef = rangeScore.clef - } - Connections { - target: rangeScore.scoreObj - onClicked: { - creator.loNote = rangeScore.scoreObj.noteAt(0) - creator.hiNote = rangeScore.scoreObj.noteAt(1) + + Grid { + id: rangeGrid + + columns: parent.width > NOO.factor() * 50 && GLOB.instrument.isGuitar ? 2 : 1 + width: parent.width + spacing: NOO.factor() / 4 + horizontalItemAlignment: Grid.AlignHCenter + topPadding: NOO.factor() + + Tframe { + width: rangeGrid.columns === 1 ? parent.width * 0.98 : parent.width * 0.49 + + Column { + width: parent.width + spacing: NOO.factor() / 2 + + Text { + text: qsTr("note range:") + color: activPal.text + anchors.horizontalCenter: parent.horizontalCenter } - } - } - } - Tile { - visible: GLOB.instrument.isGuitar - TcuteButton { - text: qsTr("adjust fret range") - anchors.horizontalCenter: parent.horizontalCenter - onClicked: creator.adjustFretsToScale() + + Item { + height: NOO.factor() * 20 + width: NOO.factor() * 12 + anchors.horizontalCenter: parent.horizontalCenter + + Score { + id: rangeScore + + anchors.fill: parent + scale: height / firstStaff.linesCount + scoreObj.editMode: true + meter: Tmeter.NoMeter + clef: creator.clef + Component.onCompleted: { + rangeScore.addNote(creator.loNote); + rangeScore.addNote(creator.hiNote); + } + + Connections { + target: rangeScore.firstStaff.clef + onClicked: creator.clef = rangeScore.clef + } + + Connections { + target: rangeScore.scoreObj + onClicked: { + creator.loNote = rangeScore.scoreObj.noteAt(0); + creator.hiNote = rangeScore.scoreObj.noteAt(1); + } + } + + } + + } + + Tile { + visible: GLOB.instrument.isGuitar + description: qsTr("Adjust fret range in a level to currently selected note range") + + TcuteButton { + text: qsTr("adjust fret range") + anchors.horizontalCenter: parent.horizontalCenter + onClicked: creator.adjustFretsToScale() + } + + } + } - description: qsTr("Adjust fret range in a level to currently selected note range") - } + } - } - Column { - visible: GLOB.instrument.isGuitar - width: rangeGrid.columns === 1 ? parent.width * 0.98 : parent.width * 0.49 - spacing: NOO.factor() / 2 - Tframe { - width: parent.width - Column { - width: parent.width + Column { + visible: GLOB.instrument.isGuitar + width: rangeGrid.columns === 1 ? parent.width * 0.98 : parent.width * 0.49 spacing: NOO.factor() / 2 - Text { text: qsTr("fret range:"); color: activPal.text; anchors.horizontalCenter: parent.horizontalCenter } - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() / 2 - Text { text: qsTr("from"); color: activPal.text; anchors.verticalCenter: parent.verticalCenter } - TspinBox { - id: loFretSpin - from: 0; to: GLOB.fretNumber - value: creator.loFret - onValueModified: { - creator.loFret = loFretSpin.value - if (loFretSpin.value > hiFretSpin.value) - creator.hiFret = loFretSpin.value - } - } - Text { text: qsTr("to"); color: activPal.text; anchors.verticalCenter: parent.verticalCenter } - TspinBox { - id: hiFretSpin - from: 0; to: GLOB.fretNumber - value: creator.hiFret - onValueModified: { - creator.hiFret = hiFretSpin.value - if (hiFretSpin.value < loFretSpin.value) - creator.loFret = hiFretSpin.value + + Tframe { + width: parent.width + + Column { + width: parent.width + spacing: NOO.factor() / 2 + + Text { + text: qsTr("fret range:") + color: activPal.text + anchors.horizontalCenter: parent.horizontalCenter + } + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() / 2 + + Text { + text: qsTr("from") + color: activPal.text + anchors.verticalCenter: parent.verticalCenter + } + + TspinBox { + id: loFretSpin + + from: 0 + to: GLOB.fretNumber + value: creator.loFret + onValueModified: { + creator.loFret = loFretSpin.value; + if (loFretSpin.value > hiFretSpin.value) + creator.hiFret = loFretSpin.value; + + } + } + + Text { + text: qsTr("to") + color: activPal.text + anchors.verticalCenter: parent.verticalCenter + } + + TspinBox { + id: hiFretSpin + + from: 0 + to: GLOB.fretNumber + value: creator.hiFret + onValueModified: { + creator.hiFret = hiFretSpin.value; + if (hiFretSpin.value < loFretSpin.value) + creator.loFret = hiFretSpin.value; + + } + } + + } + + Tile { + description: qsTr("Adjust note range in a level to currently selected fret range") + + TcuteButton { + text: qsTr("adjust note range") + anchors.horizontalCenter: parent.horizontalCenter + onClicked: creator.adjustNotesToFretRange() + } + + } + } - } + } - Tile { - TcuteButton { - text: qsTr("adjust note range") - anchors.horizontalCenter: parent.horizontalCenter - onClicked: creator.adjustNotesToFretRange() - } - description: qsTr("Adjust note range in a level to currently selected fret range") + // spacer only for 2 columns + + Item { + width: parent.width + height: rangeGrid.columns === 1 ? 0 : NOO.factor() * 3 } - } - } - Item { width: parent.width; height: rangeGrid.columns === 1 ? 0 : NOO.factor() * 3 } // spacer only for 2 columns - Tile { - description: qsTr("Uncheck strings if you want to skip them in an exam.") - Column { - width: parent.width - spacing: NOO.factor() / 4 - Text { text: qsTr("available strings:"); color: activPal.text; anchors.horizontalCenter: parent.horizontalCenter } - Grid { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - columns: Math.ceil(GLOB.tuning.stringNumber / 2.0) - horizontalItemAlignment: Grid.AlignHCenter - Repeater { - model: GLOB.tuning.stringNumber - TcheckBox { - checked: creator.usedStrings & Math.pow(2, index) - text: index + 1 - textItem.topPadding: NOO.factor() * 0.5 - font { family: "nootka"; pixelSize: NOO.factor() * 3 } - onClicked: creator.usedStrings = checked ? creator.usedStrings | Math.pow(2, index) : creator.usedStrings & ~Math.pow(2, index) - } + + Tile { + description: qsTr("Uncheck strings if you want to skip them in an exam.") + + Column { + width: parent.width + spacing: NOO.factor() / 4 + + Text { + text: qsTr("available strings:") + color: activPal.text + anchors.horizontalCenter: parent.horizontalCenter + } + + Grid { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + columns: Math.ceil(GLOB.tuning.stringNumber / 2) + horizontalItemAlignment: Grid.AlignHCenter + + Repeater { + model: GLOB.tuning.stringNumber + + TcheckBox { + checked: creator.usedStrings & Math.pow(2, index) + text: index + 1 + textItem.topPadding: NOO.factor() * 0.5 + onClicked: creator.usedStrings = checked ? creator.usedStrings | Math.pow(2, index) : creator.usedStrings & ~Math.pow(2, index) + + font { + family: "nootka" + pixelSize: NOO.factor() * 3 + } + + } + + } + + } + + } + } - } + } - } + } - } + } diff --git a/src/qml/level/RemoveLevel.qml b/src/qml/level/RemoveLevel.qml index a6bb5f8c888dda3456645a4b0c626563f4d00aaf..c00e5831627e004c9f24794be2806bcca3a5d9d5 100644 --- a/src/qml/level/RemoveLevel.qml +++ b/src/qml/level/RemoveLevel.qml @@ -2,53 +2,62 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - -import Nootka 1.0 import "../" +import Nootka 1.0 +import QtQuick 2.12 TpopupDialog { - id: rmLevel - - property string levelName - property alias levelFile: fileText.text - - signal remove(var fromDisk) - - bgColor: Qt.tint(activPal.window, NOO.alpha("red", 20)) - border { color: "red"; width: NOO.factor() / 4.0 } - visible: true; modal: true - width: innerCol.width * 1.2; height: innerCol.height + NOO.factor() * 5 - glowRect.radius: NOO.factor() - - acceptButton.text: NOO.TR("QFileDialog", "Remove") - acceptButton.pixmap: NOO.pix("delete") - - Column { - id: innerCol - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - Text { - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text - font.pixelSize: NOO.factor() * 1.5 - text: qsTr("Remove level %1 from the list").arg("<b>" + levelName + "</b>")// + "<br>" - } - TcheckBox { - id: rmFileChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("Also delete level file:") - checked: false + id: rmLevel + + property string levelName + property alias levelFile: fileText.text + + signal remove(var fromDisk) + + bgColor: Qt.tint(activPal.window, NOO.alpha("red", 20)) + visible: true + modal: true + width: innerCol.width * 1.2 + height: innerCol.height + NOO.factor() * 5 + glowRect.radius: NOO.factor() + acceptButton.text: NOO.TR("QFileDialog", "Remove") + acceptButton.pixmap: NOO.pix("delete") + onAccepted: rmLevel.remove(rmFileChB.checked) + + border { + color: "red" + width: NOO.factor() / 4 } - Text { - anchors.horizontalCenter: parent.horizontalCenter - id: fileText - color: activPal.text - font.bold: true - } - } - onAccepted: rmLevel.remove(rmFileChB.checked) -} + Column { + id: innerCol + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + Text { + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + font.pixelSize: NOO.factor() * 1.5 + text: qsTr("Remove level %1 from the list").arg("<b>" + levelName + "</b>") // + "<br>" + } + + TcheckBox { + id: rmFileChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Also delete level file:") + checked: false + } + + Text { + id: fileText + + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + font.bold: true + } + + } + +} diff --git a/src/qml/level/RhythmDiversityTile.qml b/src/qml/level/RhythmDiversityTile.qml index d5f2ba0ba184c71a7db1ad3f3d1a3e46a6e0948a..9df91998e58e706237cc93b5b9e235a06a992027 100644 --- a/src/qml/level/RhythmDiversityTile.qml +++ b/src/qml/level/RhythmDiversityTile.qml @@ -2,30 +2,36 @@ * 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 QtQuick.Controls 2.12 -import Nootka 1.0 -import "../" - Tile { - property alias diversity: rtmDivSpin.value - - signal diversityModified() - - description: qsTr("Smaller values - less number of selected rhythmic note groups will be used, biggest value - melody will consist maximal possible number of selected groups.") - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() - Text { - anchors.verticalCenter: parent.verticalCenter - text: qsTr("Rhythmic diversity") - color: enabled ? activPal.text : disdPal.text - } - TspinBox { - id: rtmDivSpin - from: 1; to: 10 - onValueModified: diversityModified() + property alias diversity: rtmDivSpin.value + + signal diversityModified() + + description: qsTr("Smaller values - less number of selected rhythmic note groups will be used, biggest value - melody will consist maximal possible number of selected groups.") + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() + + Text { + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Rhythmic diversity") + color: enabled ? activPal.text : disdPal.text + } + + TspinBox { + id: rtmDivSpin + + from: 1 + to: 10 + onValueModified: diversityModified() + } + } - } + } diff --git a/src/qml/level/RhythmsPage.qml b/src/qml/level/RhythmsPage.qml index 552054287cde4cb218a365a36140df48c4539297..4325cc2b37d1f6ee7d9074af102a986effdb5369 100644 --- a/src/qml/level/RhythmsPage.qml +++ b/src/qml/level/RhythmsPage.qml @@ -2,114 +2,149 @@ * 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.Dialogs 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 -import Nootka.Dialogs 1.0 -import "../" +Tflickable { + // Column { + // id: settCol + // anchors.verticalCenter: parent.verticalCenter + // TcheckBox { + // id: restsChB + // text: qsTr("rests") + // onClicked: restsClicked() + // } + // TcheckBox { + // id: tiesChB + // text: qsTr("ties") + // onClicked: tiesClicked() + // } + // } + id: rtmPage -Tflickable { - id: rtmPage - - contentHeight: rtmCol.height - - Column { - id: rtmCol - width: parent.width; topPadding: NOO.factor() / 2; spacing: NOO.factor() / 2 - enabled: creator.howGetMelody !== 2 && creator.melodyLen > 1 - - Text { - text: qsTr("Select any rhythm and time signature to be used in this level, otherwise melodies will not have rhythmic values, just bare note-heads.") - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - NOO.factor() * 2 - font { pixelSize: NOO.factor(); bold: true } - textFormat: Text.StyledText; horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - color: enabled ? ((rtmSel.basicMask || rtmSel.dotsMask) && metersSel.meters ? activPal.text : "red") : disdPal.text - } + contentHeight: rtmCol.height - Row { - width: parent.width; spacing: NOO.factor() / 4 - Tile { - id: selTile - anchors.horizontalCenter: undefined - width: rtmSel.width * 1.2; height: Math.max(rtmPage.height - NOO.factor() * 2, rCol.height) - RhythmSelector { - x: width / 10 - id: rtmSel - height: selTile.height - NOO.factor() * 2 - basicMask: creator.basicRhythms - dotsMask: creator.dotsRhythms - onBasicGroupChanged: creator.basicRhythms = basicMask - onDotsGroupChanged: creator.dotsRhythms = dotsMask -// useRests: creator.useRests -// onRestsClicked: creator.useRests = useRests -// useTies: creator.useTies -// onTiesClicked: creator.useTies = useTies - } - } - Column { - id: rCol - width: parent.width - selTile.width - NOO.factor() / 4; spacing: NOO.factor() / 4 - enabled: rtmSel.basicMask || rtmSel.dotsMask - Tile { - MeterSelector { - id: metersSel + Column { + id: rtmCol + + width: parent.width + topPadding: NOO.factor() / 2 + spacing: NOO.factor() / 2 + enabled: creator.howGetMelody !== 2 && creator.melodyLen > 1 + + Text { + text: qsTr("Select any rhythm and time signature to be used in this level, otherwise melodies will not have rhythmic values, just bare note-heads.") anchors.horizontalCenter: parent.horizontalCenter width: parent.width - NOO.factor() * 2 - meters: creator.meters - onMetersModified: creator.meters = meters - } - description: qsTr("Time signatures to use in this level.") - } - Tile { - description: qsTr("Number of measures in a melody. If 'variable' is set, it will grow up to the given value as an exercise or an exam is progressing.") - Row { - id: measRow - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() - Text { - anchors.verticalCenter: parent.verticalCenter - text: NOO.TR("MelGenDialog", "Measures number") - color: enabled ? activPal.text : disdPal.text + textFormat: Text.StyledText + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + color: enabled ? ((rtmSel.basicMask || rtmSel.dotsMask) && metersSel.meters ? activPal.text : "red") : disdPal.text + + font { + pixelSize: NOO.factor() + bold: true } - TspinBox { - id: barNrSpin - from: 2; to: 32 - value: creator.barNumber - onValueModified: creator.barNumber = value + + } + + Row { + width: parent.width + spacing: NOO.factor() / 4 + + Tile { + id: selTile + + anchors.horizontalCenter: undefined + width: rtmSel.width * 1.2 + height: Math.max(rtmPage.height - NOO.factor() * 2, rCol.height) + + RhythmSelector { + // useRests: creator.useRests + // onRestsClicked: creator.useRests = useRests + // useTies: creator.useTies + // onTiesClicked: creator.useTies = useTies + + id: rtmSel + + x: width / 10 + height: selTile.height - NOO.factor() * 2 + basicMask: creator.basicRhythms + dotsMask: creator.dotsRhythms + onBasicGroupChanged: creator.basicRhythms = basicMask + onDotsGroupChanged: creator.dotsRhythms = dotsMask + } + } - TcheckBox { - text: qsTr("variable") - checked: creator.variableBarNr - onClicked: creator.variableBarNr = checked + + Column { + id: rCol + + width: parent.width - selTile.width - NOO.factor() / 4 + spacing: NOO.factor() / 4 + enabled: rtmSel.basicMask || rtmSel.dotsMask + + Tile { + description: qsTr("Time signatures to use in this level.") + + MeterSelector { + id: metersSel + + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - NOO.factor() * 2 + meters: creator.meters + onMetersModified: creator.meters = meters + } + + } + + Tile { + description: qsTr("Number of measures in a melody. If 'variable' is set, it will grow up to the given value as an exercise or an exam is progressing.") + + Row { + id: measRow + + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() + + Text { + anchors.verticalCenter: parent.verticalCenter + text: NOO.TR("MelGenDialog", "Measures number") + color: enabled ? activPal.text : disdPal.text + } + + TspinBox { + id: barNrSpin + + from: 2 + to: 32 + value: creator.barNumber + onValueModified: creator.barNumber = value + } + + TcheckBox { + text: qsTr("variable") + checked: creator.variableBarNr + onClicked: creator.variableBarNr = checked + } + + } + + } + + RhythmDiversityTile { + diversity: creator.rhythmDiversity + onDiversityModified: creator.rhythmDiversity = diversity + } + } - } - } - RhythmDiversityTile { - diversity: creator.rhythmDiversity - onDiversityModified: creator.rhythmDiversity = diversity + } - } + } - } - - // Column { -// id: settCol -// anchors.verticalCenter: parent.verticalCenter -// TcheckBox { -// id: restsChB -// text: qsTr("rests") -// onClicked: restsClicked() -// } -// TcheckBox { -// id: tiesChB -// text: qsTr("ties") -// onClicked: tiesClicked() -// } -// } } - diff --git a/src/qml/nootini/AudioAnalyze.qml b/src/qml/nootini/AudioAnalyze.qml index edb59f9205fa547e4d42f83c16229a0b6cf1d856..90ea71ec20e6d9ac0e06bc8f7c3938e2054f0eb2 100644 --- a/src/qml/nootini/AudioAnalyze.qml +++ b/src/qml/nootini/AudioAnalyze.qml @@ -2,127 +2,189 @@ * 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 QtQuick.Controls 2.12 - import Nootka 1.0 import Nootka.Main 1.0 +import QtQuick 2.12 +import QtQuick.Controls 2.12 /** * To get this, invoke: * mootka --nootini */ TaudioAnalyzeItem { - id: aa - width: parent.width; height: parent.height / 2; y: parent.height - height - z: 100 - - property real sc: 1.0 - - // private - property var noteRects: [] - - Rectangle { - anchors.fill: parent - color: activPal.base - MouseArea { - anchors.fill: parent - onWheel: { - if (wheel.modifiers & Qt.ControlModifier) { - if (wheel.angleDelta.y > 0) - sc *= 1.0625 - else if (wheel.angleDelta.y < 0) - sc *= 0.9375 - } else - wheel.accepted = false - } + id: aa + + property real sc: 1 + // private + property var noteRects: [] + + width: parent.width + height: parent.height / 2 + y: parent.height - height + z: 100 + onDataReady: { + audioModel.append({ + "vol": pcmVol, + "energy": energy, + "onSet": onSet, + "note": note + }); + } + onNoteData: { + noteRects.push(noteComp.createObject(lv.contentItem, { + "width": Qt.binding(function() { + return (end - start + 1) * 5 * aa.sc; + }), + "x": Qt.binding(function() { + return start * 5 * aa.sc; + }), + "name": note + })); } - } - - ListModel { id: audioModel } - - onDataReady: { - audioModel.append( { "vol": pcmVol, "energy": energy, "onSet": onSet, "note": note } ) - } - - Shortcut { - sequence: "Shift+backspace" - onActivated: { - tip.nr = -1 - audioModel.clear() - for (var n = 0; n < noteRects.length; ++n) - noteRects[n].destroy() - noteRects.length = 0 + + Rectangle { + anchors.fill: parent + color: activPal.base + + MouseArea { + anchors.fill: parent + onWheel: { + if (wheel.modifiers & Qt.ControlModifier) { + if (wheel.angleDelta.y > 0) + sc *= 1.0625; + else if (wheel.angleDelta.y < 0) + sc *= 0.9375; + } else { + wheel.accepted = false; + } + } + } + } - } - ListView { - id: lv - anchors.fill: parent - orientation: ListView.Horizontal - boundsBehavior: Flickable.StopAtBounds + ListModel { + id: audioModel + } - model: audioModel + Shortcut { + sequence: "Shift+backspace" + onActivated: { + tip.nr = -1; + audioModel.clear(); + for (var n = 0; n < noteRects.length; ++n) noteRects[n].destroy() + noteRects.length = 0; + } + } - delegate: Rectangle { - width: 5 * aa.sc; height: aa.height - color: onSet ? "orange" : (ma.containsMouse ? "#11111111" : (vol > 0 ? "transparent" : "#110000ff")) + ListView { + id: lv - Rectangle { width: parent.width; height: (aa.height / 2) * energy; color: "#55ff0000"; y: parent.height / 2 - height } - Rectangle { width: parent.width; height: width; radius: width / 2; color: "blue"; y: parent.height * (1.0 - vol) } - MouseArea { - id: ma anchors.fill: parent - hoverEnabled: true; - onEntered: tip.nr = index - onExited: tip.nr = -1 - } + orientation: ListView.Horizontal + boundsBehavior: Flickable.StopAtBounds + model: audioModel + + Rectangle { + width: parent.width + height: 1 + color: activPal.text + y: parent.height / 2 + } + + delegate: Rectangle { + width: 5 * aa.sc + height: aa.height + color: onSet ? "orange" : (ma.containsMouse ? "#11111111" : (vol > 0 ? "transparent" : "#110000ff")) + + Rectangle { + width: parent.width + height: (aa.height / 2) * energy + color: "#55ff0000" + y: parent.height / 2 - height + } + + Rectangle { + width: parent.width + height: width + radius: width / 2 + color: "blue" + y: parent.height * (1 - vol) + } + + MouseArea { + id: ma + + anchors.fill: parent + hoverEnabled: true + onEntered: tip.nr = index + onExited: tip.nr = -1 + } + + } + } - Rectangle { width: parent.width; height: 1; color: activPal.text; y: parent.height / 2 } - } - Component { - id: noteComp - Rectangle { - property alias name: noteName.text - height: aa.height / 6; y: height / 2 - color: "transparent" - border { color: name === "\ue4e5" ? activPal.highlight : activPal.text; width: 1 } - Text { - id: noteName - color: activPal.text - font { family: "Scorek"; pixelSize: NOO.factor() * 2 } - textFormat: Text.StyledText - x: (parent.width - width) / 2; y: height * -0.2 - } + Component { + id: noteComp + + Rectangle { + property alias name: noteName.text + + height: aa.height / 6 + y: height / 2 + color: "transparent" + + border { + color: name === "\ue4e5" ? activPal.highlight : activPal.text + width: 1 + } + + Text { + id: noteName + + color: activPal.text + textFormat: Text.StyledText + x: (parent.width - width) / 2 + y: height * -0.2 + + font { + family: "Scorek" + pixelSize: NOO.factor() * 2 + } + + } + + } + } - } - - Rectangle { - id: tip - property int nr: -1 - property var mD: audioModel.get(nr) - visible: nr > -1 - border { color: activPal.text; width: 1 } - radius: NOO.factor() - width: NOO.factor() * 40; height: contText.height + NOO.factor() - x: (parent.width - width) / 2; y: -height - NOO.factor() - Text { - id: contText - anchors.centerIn: parent - color: activPal.text; textFormat: Text.StyledText - text: tip.mD ? tip.nr + "<br>note: " + tip.mD.note + "<br>volume: " + tip.mD.vol + "<br>dynamic: " + tip.mD.energy : "" + + Rectangle { + id: tip + + property int nr: -1 + property var mD: audioModel.get(nr) + + visible: nr > -1 + radius: NOO.factor() + width: NOO.factor() * 40 + height: contText.height + NOO.factor() + x: (parent.width - width) / 2 + y: -height - NOO.factor() + + border { + color: activPal.text + width: 1 + } + + Text { + id: contText + + anchors.centerIn: parent + color: activPal.text + textFormat: Text.StyledText + text: tip.mD ? tip.nr + "<br>note: " + tip.mD.note + "<br>volume: " + tip.mD.vol + "<br>dynamic: " + tip.mD.energy : "" + } + } - } - - onNoteData: { - noteRects.push(noteComp.createObject(lv.contentItem, - { - "width": Qt.binding(function() { return (end - start + 1) * 5 * aa.sc }), - "x": Qt.binding(function() { return start * 5 * aa.sc }), - "name": note - }) - ) - } } diff --git a/src/qml/score/AddLine.qml b/src/qml/score/AddLine.qml index 1981b58319ee3d9905a72cf9dad3fdbee4cf9cd6..3eff57c675b1c3d533c262d32996e26d4bea8ba4 100644 --- a/src/qml/score/AddLine.qml +++ b/src/qml/score/AddLine.qml @@ -5,8 +5,8 @@ import QtQuick 2.12 Rectangle { - x: score.singleNote ? 0.5 : - 1.0 - height: 0.2 - width: 4.0 - color: noteCursor.color + x: score.singleNote ? 0.5 : -1 + height: 0.2 + width: 4 + color: noteCursor.color } diff --git a/src/qml/score/Clef.qml b/src/qml/score/Clef.qml index ea2185a380010f163f7e554f45ee546d5c3229fd..4f7901250b89ceae2e8b9e1a1e45342a3589d158 100644 --- a/src/qml/score/Clef.qml +++ b/src/qml/score/Clef.qml @@ -2,76 +2,96 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 +import Nootka.Music import QtQuick 2.12 import QtQuick.Controls 2.12 - -import Nootka.Music -import Nootka 1.0 import Score 1.0 - Text { - id: clef + id: clef - signal clicked(var cl) + signal clicked(var cl) - width: 5.5; x: 0.5; y: 5 - text: NOO.clef(score.clef).glyph() - font { family: "Scorek"; pixelSize: 8 } - color: clefArea.containsMouse && (GLOB.singleNoteMode || scoreObj.editMode) ? GLOB.noteCursorColor : activPal.text + function getPos() { + x = 0.5; + switch (score.clef) { + case Tclef.Treble_G: + case Tclef.Treble_G_8down: + y = 5; + break; + case Tclef.Bass_F: + case Tclef.Bass_F_8down: + case Tclef.Tenor_C: + y = 1; + break; + case Tclef.Alto_C: + y = 3; + break; + case Tclef.PianoStaffClefs: + y = 3; + x = 3; + break; + case Tclef.NoClef: + y = 3; + x = 2; + break; + } + } - MouseArea { - id: clefArea + width: 5.5 + x: 0.5 y: 5 - width: parent.width; height: parent.height + (score.clef === Tclef.PianoStaffClefs ? 4 : -12) - enabled: !score.readOnly && !GLOB.isExam && (GLOB.singleNoteMode || scoreObj.editMode) - hoverEnabled: GLOB.singleNoteMode || scoreObj.editMode - property var clefDrawer - onClicked: { - if (clefDrawer) - clefDrawer.open() - else { - clefDrawer = Qt.createComponent("qrc:/score/ClefDrawer.qml").createObject(nootkaWindow.contentItem) - clefDrawer.clefMenu.clicked.connect(clef.clicked) - } - clefDrawer.selectedClef = score.clef - } - } + text: NOO.clef(score.clef).glyph() + color: clefArea.containsMouse && (GLOB.singleNoteMode || scoreObj.editMode) ? GLOB.noteCursorColor : activPal.text + Component.onCompleted: getPos() - Loader { sourceComponent: score.clef === Tclef.PianoStaffClefs ? lowerClef : null } - Component { - id: lowerClef - Text { // bass clef at lower staff - font: clef.font - text: "\ue062" - color: clef.color - y: clef.y + 15 + font { + family: "Scorek" + pixelSize: 8 } - } - Connections { target: score; onClefChanged: getPos() } - Component.onCompleted: getPos() + MouseArea { + id: clefArea - function getPos() { - x = 0.5 - switch (score.clef) { - case Tclef.Treble_G: - case Tclef.Treble_G_8down: - y = 5; break; - case Tclef.Bass_F: - case Tclef.Bass_F_8down: - case Tclef.Tenor_C: - y = 1; break; - case Tclef.Alto_C: - y = 3; break; - case Tclef.PianoStaffClefs: - y = 3; x = 3; break; - case Tclef.NoClef: - y = 3; x = 2; break; + property var clefDrawer + + y: 5 + width: parent.width + height: parent.height + (score.clef === Tclef.PianoStaffClefs ? 4 : -12) + enabled: !score.readOnly && !GLOB.isExam && (GLOB.singleNoteMode || scoreObj.editMode) + hoverEnabled: GLOB.singleNoteMode || scoreObj.editMode + onClicked: { + if (clefDrawer) { + clefDrawer.open(); + } else { + clefDrawer = Qt.createComponent("qrc:/score/ClefDrawer.qml").createObject(nootkaWindow.contentItem); + clefDrawer.clefMenu.clicked.connect(clef.clicked); + } + clefDrawer.selectedClef = score.clef; + } + } + + Loader { + sourceComponent: score.clef === Tclef.PianoStaffClefs ? lowerClef : null } - } -} + Component { + id: lowerClef + // bass clef at lower staff + Text { + font: clef.font + text: "\ue062" + color: clef.color + y: clef.y + 15 + } + } + + Connections { + target: score + onClefChanged: getPos() + } +} diff --git a/src/qml/score/ClefDrawer.qml b/src/qml/score/ClefDrawer.qml index 20a199080ae41daeaf2e4f989e087dd8849d3065..fd42a73159963c7b102ed5f2058b2f807e8fa977 100644 --- a/src/qml/score/ClefDrawer.qml +++ b/src/qml/score/ClefDrawer.qml @@ -19,7 +19,7 @@ Drawer { ClefMenu { id: clefMenu - onClicked: cl => { + onClicked: (cl) => { close(); score.clef = cl; } diff --git a/src/qml/score/ControlBase.qml b/src/qml/score/ControlBase.qml index edf0a96b0310d43ffcf76b2a1730333d2986e368..7c08b85b5fb1cd9d3d993673a24aaa7928975a18 100644 --- a/src/qml/score/ControlBase.qml +++ b/src/qml/score/ControlBase.qml @@ -2,47 +2,48 @@ * 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.Window 2.12 -import Nootka 1.0 -import "../" - - GlowRect { - id: base - property bool active: false - property real factor: Screen.pixelDensity * (NOO.isAndroid() ? 2.5 : 3.5) - property alias component: loader.sourceComponent - property alias hideTimer: hideTimer - property alias loader: loader - - // protected - property bool show: false - - z: 20 - width: loader.item ? loader.item.width : 0 - height: loader.item ?loader.item.height : 0 - color: activPal.alternateBase - - Loader { - id: loader - active: false - } - - onActiveChanged: { - if (active) { - loader.active = true - show = true - hideTimer.stop() - } else - hideTimer.restart() - } - - Timer { - id: hideTimer - interval: 1000 - repeat: false - onTriggered: show = false - } + id: base + + property bool active: false + property real factor: Screen.pixelDensity * (NOO.isAndroid() ? 2.5 : 3.5) + property alias component: loader.sourceComponent + property alias hideTimer: hideTimer + property alias loader: loader + // protected + property bool show: false + + z: 20 + width: loader.item ? loader.item.width : 0 + height: loader.item ? loader.item.height : 0 + color: activPal.alternateBase + onActiveChanged: { + if (active) { + loader.active = true; + show = true; + hideTimer.stop(); + } else { + hideTimer.restart(); + } + } + + Loader { + id: loader + + active: false + } + + Timer { + id: hideTimer + + interval: 1000 + repeat: false + onTriggered: show = false + } + } diff --git a/src/qml/score/ControlButton.qml b/src/qml/score/ControlButton.qml index da056556be74d39d50b4c7d457a65ec2515e77d2..7faba5769791ec9f0ae41cb7a9f0bece65dd5fa7 100644 --- a/src/qml/score/ControlButton.qml +++ b/src/qml/score/ControlButton.qml @@ -2,57 +2,76 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 +import QtQuick 2.12 Rectangle { - id: cb - - property real factor: 1 - property bool selected: false - property alias text: txt.text - property alias font: txt.font - property alias textHeight: txt.height - property alias textColor: txt.color - property alias yOffset: txt.y - property string statusTip - property int tipPos: Item.Top - - signal entered() - signal exited() - signal clicked() - - color: selected ? activPal.highlight : "transparent" - width: factor * 2 - height: factor * 3 - radius: factor / 5 - - scale: ma.containsMouse ? (ma.pressed ? 0.8 : 1.5) : 1 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - Behavior on color { enabled: GLOB.useAnimations; ColorAnimation { duration: 150 }} - - Text { - id: txt - x: (cb.width - width) / 2 - style: Text.Normal - color: cb.enabled ? activPal.text : disdPal.text - } - - MouseArea { - id: ma - anchors.fill: parent - hoverEnabled: true - onClicked: cb.clicked() - onEntered: { - cb.entered() - if (statusTip !== "") - NOO.setStatusTip(statusTip, Item.TopLeft) + id: cb + + property real factor: 1 + property bool selected: false + property alias text: txt.text + property alias font: txt.font + property alias textHeight: txt.height + property alias textColor: txt.color + property alias yOffset: txt.y + property string statusTip + property int tipPos: Item.Top + + signal entered() + signal exited() + signal clicked() + + color: selected ? activPal.highlight : "transparent" + width: factor * 2 + height: factor * 3 + radius: factor / 5 + scale: ma.containsMouse ? (ma.pressed ? 0.8 : 1.5) : 1 + + Text { + id: txt + + x: (cb.width - width) / 2 + style: Text.Normal + color: cb.enabled ? activPal.text : disdPal.text } - onExited: { - cb.exited() - if (statusTip !== "") - NOO.setStatusTip("", Item.TopLeft) + + MouseArea { + id: ma + + anchors.fill: parent + hoverEnabled: true + onClicked: cb.clicked() + onEntered: { + cb.entered(); + if (statusTip !== "") + NOO.setStatusTip(statusTip, Item.TopLeft); + + } + onExited: { + cb.exited(); + if (statusTip !== "") + NOO.setStatusTip("", Item.TopLeft); + + } + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + } - } + + Behavior on color { + enabled: GLOB.useAnimations + + ColorAnimation { + duration: 150 + } + + } + } diff --git a/src/qml/score/DelControl.qml b/src/qml/score/DelControl.qml index c6da39024e7c5523add1a656856b45c0dbe06a84..de1c42562b77733e1d944e6804f6fce21df23642 100644 --- a/src/qml/score/DelControl.qml +++ b/src/qml/score/DelControl.qml @@ -2,73 +2,110 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" import QtQuick 2.12 - import Score 1.0 -import "../" - ControlBase { - id: delControl - - visible: show - - property var activeItem: null - - Connections { - target: scoreObj - enabled: !scoreObj.singleNote && scoreObj.allowAdding && !scoreObj.readOnly - onEditModeChanged: delControl.show = scoreObj.editMode && activeItem - onActiveNoteChanged: { - if (scoreObj.activeNote) { - if (!scoreObj.readOnly && activeItem != scoreObj.activeNote) { - activeItem = scoreObj.activeNote - delControl.x = (activeItem.x + activeItem.width) * score.scale - delControl.y = activeItem.staffItem.y + score.scale * 6 - delControl.active = true - } - } else if (activeItem) { - delControl.active = false - } + id: delControl + + property var activeItem: null + + visible: show + hideTimer.onTriggered: activeItem = null + + Connections { + target: scoreObj + enabled: !scoreObj.singleNote && scoreObj.allowAdding && !scoreObj.readOnly + onEditModeChanged: delControl.show = scoreObj.editMode && activeItem + onActiveNoteChanged: { + if (scoreObj.activeNote) { + if (!scoreObj.readOnly && activeItem != scoreObj.activeNote) { + activeItem = scoreObj.activeNote; + delControl.x = (activeItem.x + activeItem.width) * score.scale; + delControl.y = activeItem.staffItem.y + score.scale * 6; + delControl.active = true; + } + } else if (activeItem) { + delControl.active = false; + } + } + onScoreWasCleared: show = false } - onScoreWasCleared: show = false - } - - hideTimer.onTriggered: activeItem = null - - component: Component { - id: contentComp - Column { - ControlButton { - factor: delControl.factor - font { family: "Nootka"; pixelSize: factor * 3 } - text: "o" - textColor: "red" - onClicked: { scoreObj.deleteNote(activeItem); show = false } - Component.onCompleted: { - if (scoreObj.deleteNoteAct) - statusTip = scoreObj.deleteNoteAct.text + ".<br><b>(" + scoreObj.deleteNoteAct.key() + ")</b>" + + GlowRect { + x: activeItem ? -activeItem.width * score.scale - width * 1.3 : 0 + width: controlButt.width + height: controlButt.height + + ControlButton { + id: controlButt + + factor: delControl.factor + text: "n" + textColor: activPal.text + onClicked: { + scoreObj.insertNote(activeItem); + delControl.show = false; + } + Component.onCompleted: { + if (scoreObj.insertNoteAct) + statusTip = scoreObj.insertNoteAct.text + "<br><b>(" + scoreObj.insertNoteAct.key() + ")</b>"; + + } + + font { + family: "Nootka" + pixelSize: factor * 3 + } + + Rectangle { + y: factor / 10 + x: factor / 2 + height: factor + width: factor / 6 + color: "green" + } + + Rectangle { + y: factor / 2 + x: factor / 10 + width: factor + height: factor / 6 + color: "green" + } + } - } + } - } - - GlowRect { - x: activeItem ? -activeItem.width * score.scale - width * 1.3: 0 - width: controlButt.width; height: controlButt.height - ControlButton { - id: controlButt - factor: delControl.factor - font { family: "Nootka"; pixelSize: factor * 3 } - text: "n" - textColor: activPal.text - onClicked: { scoreObj.insertNote(activeItem); delControl.show = false } - Rectangle { y: factor / 10; x: factor / 2; height: factor; width: factor / 6; color: "green" } - Rectangle { y: factor / 2; x: factor / 10; width: factor; height: factor / 6; color: "green" } - Component.onCompleted: { - if (scoreObj.insertNoteAct) - statusTip = scoreObj.insertNoteAct.text + "<br><b>(" + scoreObj.insertNoteAct.key() + ")</b>" - } + + component: Component { + id: contentComp + + Column { + ControlButton { + factor: delControl.factor + text: "o" + textColor: "red" + onClicked: { + scoreObj.deleteNote(activeItem); + show = false; + } + Component.onCompleted: { + if (scoreObj.deleteNoteAct) + statusTip = scoreObj.deleteNoteAct.text + ".<br><b>(" + scoreObj.deleteNoteAct.key() + ")</b>"; + + } + + font { + family: "Nootka" + pixelSize: factor * 3 + } + + } + + } + } - } + } diff --git a/src/qml/score/DummyChord.qml b/src/qml/score/DummyChord.qml index d99bd8185d5e4b31a4de1bb651b28b5332bd7169..4a808ec9f234ae0dfd8b5f91a69a12c96c9a805e 100644 --- a/src/qml/score/DummyChord.qml +++ b/src/qml/score/DummyChord.qml @@ -2,50 +2,72 @@ * 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 Nootka 1.0 +import QtQuick 2.12 import Score 1.0 - TdummyChord { - id: chordIt - - anchors.fill: parent - - // private - property var chV: importWindow.chordView - - Rectangle { - //anchors.fill: parent - width: parent.width + 2; height: loPosY - hiPosY + 8 - x: -1; y: hiPosY - 4 - radius: width / 4 - color: NOO.alpha(chV && chV.visible && chV.chordIt == chordIt ? activPal.highlight : activPal.dimText, ma.containsMouse ? 60 : 30) - } - - Repeater { - model: chordModel - Text { - scale: index === selected ? 1.4 : 1.2 - font { family: "Scorek"; pixelSize: 7 } - text: noteHead - y: headPos(index) - 15 + (chordIt.parent ? 0 : 0) // force to refresh note-heads position - color: index === selected ? activPal.text : activPal.dimText - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { }} - Text { - font { family: "Scorek"; pixelSize: 7 } - color: parent.color - x: -width - 0.1 - text: index > 0 ? alterText(index) : "" - } - } - } + id: chordIt + + // private + property var chV: importWindow.chordView - MouseArea { - id: ma anchors.fill: parent - hoverEnabled: !NOO.isAndroid() - onClicked: importWindow.showChord(chordIt) - } + + Rectangle { + //anchors.fill: parent + width: parent.width + 2 + height: loPosY - hiPosY + 8 + x: -1 + y: hiPosY - 4 + radius: width / 4 + color: NOO.alpha(chV && chV.visible && chV.chordIt == chordIt ? activPal.highlight : activPal.dimText, ma.containsMouse ? 60 : 30) + } + + Repeater { + model: chordModel + + Text { + scale: index === selected ? 1.4 : 1.2 + text: noteHead + y: headPos(index) - 15 + (chordIt.parent ? 0 : 0) // force to refresh note-heads position + color: index === selected ? activPal.text : activPal.dimText + + font { + family: "Scorek" + pixelSize: 7 + } + + Text { + color: parent.color + x: -width - 0.1 + text: index > 0 ? alterText(index) : "" + + font { + family: "Scorek" + pixelSize: 7 + } + + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + } + + } + + } + + } + + MouseArea { + id: ma + + anchors.fill: parent + hoverEnabled: !NOO.isAndroid() + onClicked: importWindow.showChord(chordIt) + } + } diff --git a/src/qml/score/KeySignature.qml b/src/qml/score/KeySignature.qml index 6d939fff878d97ed153973694802ec306c80a9a1..a8b073e6a9d93619e2504a65ec3be626f4f85ab0 100644 --- a/src/qml/score/KeySignature.qml +++ b/src/qml/score/KeySignature.qml @@ -2,103 +2,155 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 +import Nootka.Music import QtQuick 2.12 import QtQuick.Controls 2.12 - -import Nootka 1.0 import Score 1.0 -import Nootka.Music Item { - id: keySig - -// private - readonly property var sharpPos: [ 0, 3, -1, 2, 5, 1, 4 ] - readonly property var flatPos: [ 4, 1, 5, 2, 6, 3, 7 ] - - x: staff.clef.x + staff.clef.width + 1 - width: Math.max(6, (Math.abs(score.keySignature) + 1) * 1.8) - height: 10 - - function accidOffset(c) { - var accidOff = 1 - switch (c) { - case Tclef.Bass_F: - case Tclef.Bass_F_8down: - accidOff = -1; break; - case Tclef.Tenor_C: - accidOff = 2; break; - case Tclef.Alto_C: - accidOff = 0; break; - case Tclef.PianoStaffClefs: - accidOff = 3; break; + id: keySig + + // private + readonly property var sharpPos: [0, 3, -1, 2, 5, 1, 4] + readonly property var flatPos: [4, 1, 5, 2, 6, 3, 7] + + function accidOffset(c) { + var accidOff = 1; + switch (c) { + case Tclef.Bass_F: + case Tclef.Bass_F_8down: + accidOff = -1; + break; + case Tclef.Tenor_C: + accidOff = 2; + break; + case Tclef.Alto_C: + accidOff = 0; + break; + case Tclef.PianoStaffClefs: + accidOff = 3; + break; + } + return accidOff; } - return accidOff; - } - - Loader { sourceComponent: accidsComp; y: 0 } - Loader { sourceComponent: score.clef === Tclef.PianoStaffClefs ? accidsComp : null; y: 12 } - - Component { - id: accidsComp - Repeater { - model: 7 - Text { - font { family: "Scorek"; pixelSize: 8 } - color: activPal.text - text: score.keySignature < 0 ? "\ue260" : (score.keySignature > 0 ? "\ue262" : "") // flat or sharp symbols - x: index * 1.8 - y: parent.y + (score.keySignature < 0 ? flatPos[index] : sharpPos[index]) - accidOffset(score.clef) - + (score.clef === Tclef.Tenor_C && score.keySignature > 0 && (index === 0 || index === 2) ? 7 : 0) - opacity: index < Math.abs(score.keySignature) ? 1.0 : 0.0 - Behavior on opacity { enabled: GLOB.useAnimations; NumberAnimation { property: "opacity"; duration: 300 }} - } + + function keyUp() { + if (score.keySignature < 7) + ++score.keySignature; + } - } - - Loader { sourceComponent: mAreaComp; y: 13 } - Loader { sourceComponent: score.clef === Tclef.PianoStaffClefs ? mAreaComp : null; y: 34 } - - Component { - id: mAreaComp - MouseArea { // area at lower staff - width: keySig.width; height: 14 - enabled: !scoreObj.readOnly && !scoreObj.keyReadOnly && (GLOB.singleNoteMode || scoreObj.editMode) - hoverEnabled: true - onClicked: { - if (mouseY < 7) - keyUp() - else - keyDown() - } - onWheel: { - if (wheel.angleDelta.y > 0) - deltaUp() - else if (wheel.angleDelta.y < 0) - deltaDown() - } - onEntered: NOO.setStatusTip(qsTr("Key signature - to change it, click above or below the staff or use mouse wheel."), Item.TopLeft) - onExited: NOO.setStatusTip("", Item.TopLeft) + + function keyDown() { + if (score.keySignature > -7) + --score.keySignature; + } - } - // stops switching keys too quick (by wheel on touch pad) - Timer { id: wheelTimer; interval: 250 } + function deltaUp() { + if (!wheelTimer.running) { + keyUp(); + wheelTimer.running = true; + } + } - function keyUp() { if (score.keySignature < 7) ++score.keySignature } - function keyDown() { if (score.keySignature > -7) --score.keySignature } + function deltaDown() { + if (!wheelTimer.running) { + keyDown(); + wheelTimer.running = true; + } + } - function deltaUp() { - if (!wheelTimer.running) { - keyUp() - wheelTimer.running = true + x: staff.clef.x + staff.clef.width + 1 + width: Math.max(6, (Math.abs(score.keySignature) + 1) * 1.8) + height: 10 + + Loader { + sourceComponent: accidsComp + y: 0 } - } - function deltaDown() { - if (!wheelTimer.running) { - keyDown() - wheelTimer.running = true + Loader { + sourceComponent: score.clef === Tclef.PianoStaffClefs ? accidsComp : null + y: 12 } - } + + Component { + id: accidsComp + + Repeater { + model: 7 + + Text { + color: activPal.text + text: score.keySignature < 0 ? "\ue260" : (score.keySignature > 0 ? "\ue262" : "") // flat or sharp symbols + x: index * 1.8 + y: parent.y + (score.keySignature < 0 ? flatPos[index] : sharpPos[index]) - accidOffset(score.clef) + (score.clef === Tclef.Tenor_C && score.keySignature > 0 && (index === 0 || index === 2) ? 7 : 0) + opacity: index < Math.abs(score.keySignature) ? 1 : 0 + + font { + family: "Scorek" + pixelSize: 8 + } + + Behavior on opacity { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "opacity" + duration: 300 + } + + } + + } + + } + + } + + Loader { + sourceComponent: mAreaComp + y: 13 + } + + Loader { + sourceComponent: score.clef === Tclef.PianoStaffClefs ? mAreaComp : null + y: 34 + } + + Component { + id: mAreaComp + + // area at lower staff + MouseArea { + width: keySig.width + height: 14 + enabled: !scoreObj.readOnly && !scoreObj.keyReadOnly && (GLOB.singleNoteMode || scoreObj.editMode) + hoverEnabled: true + onClicked: { + if (mouseY < 7) + keyUp(); + else + keyDown(); + } + onWheel: { + if (wheel.angleDelta.y > 0) + deltaUp(); + else if (wheel.angleDelta.y < 0) + deltaDown(); + } + onEntered: NOO.setStatusTip(qsTr("Key signature - to change it, click above or below the staff or use mouse wheel."), Item.TopLeft) + onExited: NOO.setStatusTip("", Item.TopLeft) + } + + } + + // stops switching keys too quick (by wheel on touch pad) + Timer { + id: wheelTimer + + interval: 250 + } + } diff --git a/src/qml/score/MelGenDialog.qml b/src/qml/score/MelGenDialog.qml index 82f0d92a76df79b7cc2d2b6ee73791c5dade2b99..8fa6e3738f75e4ff1d282b7ef5b0a471c4975dde 100644 --- a/src/qml/score/MelGenDialog.qml +++ b/src/qml/score/MelGenDialog.qml @@ -2,122 +2,157 @@ * 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 QtQuick.Controls 2.12 - -import Nootka 1.0 -import Nootka.Dialogs 1.0 import "../" import "../level" +import Nootka 1.0 +import Nootka.Dialogs 1.0 +import QtQuick 2.12 +import QtQuick.Controls 2.12 TmelGenItem { - id: melGenItem + id: melGenItem + + property var genButt: null - width: parent.width; height: parent.height + function help() { + NOO.openDocLink("2017/05/17/melody-generator/"); + } - rhythmSelector: rtmSel + function reset() { + } - Tflickable { + width: parent.width height: parent.height - contentHeight: mainCol.height - - Column { - id: mainCol - leftPadding: NOO.factor() / 2 - Row { - Tile { - id: selTile - visible: hasRhythms() - anchors.horizontalCenter: undefined - width: rtmSel.width * 1.2; height: Math.max(melGenItem.height, rCol.height) - RhythmSelector { - id: rtmSel - x: width / 10 - height: selTile.height * 0.95 - } - } + rhythmSelector: rtmSel + Component.onCompleted: { + dialLoader.title = NOO.TR("TmelodySettings", "Random melody"); + dialLoader.standardButtons = DialogButtonBox.Close | DialogButtonBox.Help | DialogButtonBox.RestoreDefaults; + genButt = dialLoader.buttonBox.standardButton(DialogButtonBox.RestoreDefaults); + genButt.text = NOO.TR("TmainScoreObject", "Generate melody"); + genButt.pixmap = NOO.pix("melody"); + } + + Tflickable { + height: parent.height + contentHeight: mainCol.height + Column { - id: rCol - width: melGenItem.width - (hasRhythms() ? selTile.width : 0) - NOO.factor() - topPadding: hasRhythms() ? 0 : NOO.factor() * 2 - Tile { - visible: hasRhythms() - Row { - id: measRow - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() - Text { - anchors.verticalCenter: parent.verticalCenter - text: qsTr("Measures number") - color: enabled ? activPal.text : disdPal.text - } - TspinBox { - from: 2; to: 32 - value: barNumber - onValueModified: barNumber = value - } - } - } - RhythmDiversityTile { - visible: hasRhythms() - diversity: rhythmDiversity - onDiversityModified: rhythmDiversity = diversity - } - Tile { - visible: !hasRhythms() + id: mainCol + + leftPadding: NOO.factor() / 2 + Row { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - Text { - text: NOO.TR("MelodyPage", "Melody length") - anchors.verticalCenter: parent.verticalCenter - } - TspinBox { - id: lenSpin - from: 2; to: 50 - value: length - onValueModified: length = value - } + Tile { + id: selTile + + visible: hasRhythms() + anchors.horizontalCenter: undefined + width: rtmSel.width * 1.2 + height: Math.max(melGenItem.height, rCol.height) + + RhythmSelector { + id: rtmSel + + x: width / 10 + height: selTile.height * 0.95 + } + + } + + Column { + id: rCol + + width: melGenItem.width - (hasRhythms() ? selTile.width : 0) - NOO.factor() + topPadding: hasRhythms() ? 0 : NOO.factor() * 2 + + Tile { + visible: hasRhythms() + + Row { + id: measRow + + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() + + Text { + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Measures number") + color: enabled ? activPal.text : disdPal.text + } + + TspinBox { + from: 2 + to: 32 + value: barNumber + onValueModified: barNumber = value + } + + } + + } + + RhythmDiversityTile { + visible: hasRhythms() + diversity: rhythmDiversity + onDiversityModified: rhythmDiversity = diversity + } + + Tile { + visible: !hasRhythms() + + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + Text { + text: NOO.TR("MelodyPage", "Melody length") + anchors.verticalCenter: parent.verticalCenter + } + + TspinBox { + id: lenSpin + + from: 2 + to: 50 + value: length + onValueModified: length = value + } + + } + + } + + EndOnTonicTile { + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width + checked: endsOnTonic + checkBox.onClicked: endsOnTonic = checked + } + + CurrentKeyTile { + checked: onlyCurrKey + checkBox.onClicked: onlyCurrKey = checked + } + + MaxIntervalTile { + maxStep: melGenItem.maxStep + onMaxModified: melGenItem.maxStep = maxStep + } + + } + } - } - EndOnTonicTile { - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - checked: endsOnTonic - checkBox.onClicked: endsOnTonic = checked - } - CurrentKeyTile { - checked: onlyCurrKey - checkBox.onClicked: onlyCurrKey = checked - } - MaxIntervalTile { - maxStep: melGenItem.maxStep - onMaxModified: melGenItem.maxStep = maxStep - } + } - } - } - } - - property var genButt: null - - Component.onCompleted: { - dialLoader.title = NOO.TR("TmelodySettings", "Random melody") - dialLoader.standardButtons = DialogButtonBox.Close | DialogButtonBox.Help | DialogButtonBox.RestoreDefaults - genButt = dialLoader.buttonBox.standardButton(DialogButtonBox.RestoreDefaults) - genButt.text = NOO.TR("TmainScoreObject", "Generate melody") - genButt.pixmap = NOO.pix("melody") - } - - Connections { - target: genButt - onClicked: { - generate() - dialLoader.close() + } - } - function help() { NOO.openDocLink("2017/05/17/melody-generator/") } + Connections { + target: genButt + onClicked: { + generate(); + dialLoader.close(); + } + } - function reset() {} } diff --git a/src/qml/score/MelodyImport.qml b/src/qml/score/MelodyImport.qml index bc5bcd8bd2b6c50cee2b360bff2e47266c5eb562..33f82a426e2086c91a6b4fed06c3b2094c32acab 100644 --- a/src/qml/score/MelodyImport.qml +++ b/src/qml/score/MelodyImport.qml @@ -2,402 +2,599 @@ * Copyright (C) 2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" +import "../score" +import Nootka 1.0 +import Nootka.Dialogs 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Window 2.12 - -import Nootka 1.0 -import Nootka.Dialogs 1.0 import Score 1.0 -import "../" -import "../score" - Window { - id: importWindow - property alias multiSelect: melImport.multiSelect - - visibility: NOO.isAndroid() && GLOB.fullScreen() ? "FullScreen" : "AutomaticVisibility" - visible: true - modality: Qt.WindowModal - title: qsTr("Import of musical score") - width: nootkaWindow.width; height: nootkaWindow.height; x: nootkaWindow.x; y: nootkaWindow.y - color: activPal.window - - ButtonGroup { id: group } - - TmelodyImportItem { - id: melImport - anchors.fill: parent - Text { - id: melTitle - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text - font { pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.2); bold: true } - text: melImport.title + // It covers both cases: when model are ready before dialog and ready only after this onCompleted + + id: importWindow + + property alias multiSelect: melImport.multiSelect + property var dividePop: null + property var transPop: null + property var allChordsPop + property var chordView: null + + function showChord(chordIt) { + if (!chordView) + chordView = chordComp.createObject(importWindow); + + chordView.chordIt = chordIt; + chordView.open(); } - ListView { - id: partList - y: melTitle.height + NOO.factor() * (NOO.isAndroid() ? 1.1 : 2) - width: parent.width; height: parent.height - melTitle.height - buttRow.height - NOO.factor() * 2.5 - clip: true - spacing: NOO.factor() / (NOO.isAndroid() ? 4 : 2) - //model: // apply model only when entire window is created - delegate: TipRect { - x: NOO.factor() / 4 - width: melImport.width - NOO.factor() / 2; height: scoreCol.height + NOO.factor() + + visibility: NOO.isAndroid() && GLOB.fullScreen() ? "FullScreen" : "AutomaticVisibility" + visible: true + modality: Qt.WindowModal + title: qsTr("Import of musical score") + width: nootkaWindow.width + height: nootkaWindow.height + x: nootkaWindow.x + y: nootkaWindow.y + color: activPal.window + Component.onCompleted: { + melImport.importWindowReady(); + if (GLOB.gotIt("ScoreImport", true)) + Qt.createComponent("qrc:/gotit/ImportInfo.qml").createObject(importWindow, { + "remaindChecked": true + }); + + if (melImport.partsModel.length === 0) + busyComp.createObject(melImport); + + partList.model = Qt.binding(function() { + return melImport.partsModel; + }); + } + onClosing: destroy() + + ButtonGroup { + id: group + } + + TmelodyImportItem { + id: melImport + + anchors.fill: parent + Text { - z: 5; x: NOO.factor() * 2 - color: activPal.text - text: modelData.partName + id: melTitle + + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + text: melImport.title + + font { + pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.2) + bold: true + } + } - Column { - id: scoreCol - width: parent.width - z: 1 - Repeater { - model: modelData.snippets - Rectangle { - width: parent.width; height: score.height + NOO.factor() - color: NOO.alpha(activPal.highlight, importChB.checked ? 50 : 0) - TcheckBox { - id: importChB - enabled: modelData.unsupported === 0 - anchors.verticalCenter: parent.verticalCenter - ButtonGroup.group: multiSelect ? null : group - } - Score { - id: score - y: NOO.factor() / 2; x: importChB.width + NOO.factor() - width: melImport.width - importChB.width - NOO.factor() * 1.5 - height: NOO.isAndroid() ? Math.min(NOO.factor() * 8, importWindow.height / 3) : NOO.factor() * 15 - readOnly: true - bgColor: "transparent" - } - Component.onCompleted: { - modelData.setScoreObject(score.scoreObj) - modelData.selected = Qt.binding(function() { return importChB.checked }) - if (modelData.unsupported) - unsuppComp.createObject(this) - } + + ListView { + id: partList + + y: melTitle.height + NOO.factor() * (NOO.isAndroid() ? 1.1 : 2) + width: parent.width + height: parent.height - melTitle.height - buttRow.height - NOO.factor() * 2.5 + clip: true + spacing: NOO.factor() / (NOO.isAndroid() ? 4 : 2) + + //model: // apply model only when entire window is created + delegate: TipRect { + x: NOO.factor() / 4 + width: melImport.width - NOO.factor() / 2 + height: scoreCol.height + NOO.factor() + + Text { + z: 5 + x: NOO.factor() * 2 + color: activPal.text + text: modelData.partName + } + + Column { + id: scoreCol + + width: parent.width + z: 1 + + Repeater { + model: modelData.snippets + + Rectangle { + width: parent.width + height: score.height + NOO.factor() + color: NOO.alpha(activPal.highlight, importChB.checked ? 50 : 0) + Component.onCompleted: { + modelData.setScoreObject(score.scoreObj); + modelData.selected = Qt.binding(function() { + return importChB.checked; + }); + if (modelData.unsupported) + unsuppComp.createObject(this); + + } + + TcheckBox { + id: importChB + + enabled: modelData.unsupported === 0 + anchors.verticalCenter: parent.verticalCenter + ButtonGroup.group: multiSelect ? null : group + } + + Score { + id: score + + y: NOO.factor() / 2 + x: importChB.width + NOO.factor() + width: melImport.width - importChB.width - NOO.factor() * 1.5 + height: NOO.isAndroid() ? Math.min(NOO.factor() * 8, importWindow.height / 3) : NOO.factor() * 15 + readOnly: true + bgColor: "transparent" + } + + } + + } + + } + + Rectangle { + z: 7 + width: childrenRect.width + height: childrenRect.height + radius: height / 4 + color: NOO.alpha(activPal.base, 200) + + anchors { + right: parent.right + top: parent.top + margins: NOO.factor() / 2 + } + + // single part actions for 'Divide' & 'Transpose' + Row { + RectButton { + height: NOO.factor() * (NOO.isAndroid() ? 1.8 : 2.2) + text: "\u2702" + onClicked: { + if (!dividePop) + dividePop = divideComp.createObject(importWindow); + + var p = parent.mapToItem(partList, 0, (NOO.factor() * 15 - dividePop.height) / 2); + dividePop.melPart = modelData; + dividePop.x = partList.width - dividePop.width - NOO.factor() * 4; + dividePop.y = NOO.bound(0, p.y, partList.height - dividePop.height); + dividePop.open(); + } + + font { + pixelSize: NOO.factor() * (NOO.isAndroid() ? 1.5 : 2) + family: "Nootka" + } + + } + + RectButton { + height: NOO.factor() * (NOO.isAndroid() ? 1.8 : 2.2) + text: "\u0192" + onClicked: { + if (!transPop) + transPop = transComp.createObject(importWindow); + + var p = parent.mapToItem(partList, 0, 0); + transPop.melPart = modelData; + transPop.initialKey = modelData.key; + transPop.x = partList.width - transPop.width - NOO.factor() * 4; + transPop.y = p.y; + transPop.open(); + } + + font { + pixelSize: NOO.factor() * (NOO.isAndroid() ? 1.5 : 2) + family: "Nootka" + } + + } + + RectButton { + height: NOO.factor() * (NOO.isAndroid() ? 1.8 : 2.2) + text: "\u0193" + onClicked: { + if (!allChordsPop) + allChordsPop = allChordsComp.createObject(importWindow); + + var p = parent.mapToItem(partList, 0, 0); + allChordsPop.melPart = modelData; + allChordsPop.x = partList.width - allChordsPop.width - NOO.factor() * 4; + allChordsPop.y = p.y; + allChordsPop.open(); + } + + font { + pixelSize: NOO.factor() * (NOO.isAndroid() ? 1.5 : 2) + family: "Nootka" + } + + } + + } + + } + + } + + ScrollBar.vertical: ScrollBar { } - } + } - Rectangle { - anchors { right: parent.right; top: parent.top; margins: NOO.factor() / 2 } - z: 7 - width: childrenRect.width; height: childrenRect.height; radius: height / 4 - color: NOO.alpha(activPal.base, 200) - Row { // single part actions for 'Divide' & 'Transpose' - RectButton { - height: NOO.factor() * (NOO.isAndroid() ? 1.8 : 2.2) - font { pixelSize: NOO.factor() * (NOO.isAndroid() ? 1.5 : 2); family: "Nootka" } - text: "\u2702" - onClicked: { - if (!dividePop) - dividePop = divideComp.createObject(importWindow) - var p = parent.mapToItem(partList, 0, (NOO.factor() * 15 - dividePop.height) / 2) - dividePop.melPart = modelData - dividePop.x = partList.width - dividePop.width - NOO.factor() * 4 - dividePop.y = NOO.bound(0, p.y, partList.height - dividePop.height) - dividePop.open() - } + + // Footer with 'Import' & 'Cancel' buttons + Row { + id: buttRow + + y: parent.height - height - NOO.factor() / 2 + x: (parent.width - width) / 2 + spacing: NOO.factor() * 2 + + TiconButton { + y: NOO.factor() / 4 + pixmap: NOO.pix("exit") + text: NOO.TR("QShortcut", "Cancel") + color: Qt.tint(activPal.button, NOO.alpha("red", NOO.isAndroid() ? 40 : 0)) + onClicked: close() } + + TiconButton { + y: NOO.factor() / 4 + pixmap: NOO.pix("melody") + text: qsTr("Import") + color: Qt.tint(activPal.button, NOO.alpha("teal", NOO.isAndroid() ? 40 : 0)) + onClicked: { + melImport.emitImport(); + close(); + } + } + + } + + // Global 'Divide' action + Row { + anchors { + left: parent.left + top: parent.top + topMargin: NOO.factor() / 4 + leftMargin: NOO.factor() / 2 + } + RectButton { - height: NOO.factor() * (NOO.isAndroid() ? 1.8 : 2.2) - font { pixelSize: NOO.factor() * (NOO.isAndroid() ? 1.5 : 2); family: "Nootka" } - text: "\u0192" - onClicked: { - if (!transPop) - transPop = transComp.createObject(importWindow) - var p = parent.mapToItem(partList, 0, 0) - transPop.melPart = modelData - transPop.initialKey = modelData.key - transPop.x = partList.width - transPop.width - NOO.factor() * 4 - transPop.y = p.y - transPop.open() - } + height: NOO.factor() * (NOO.isAndroid() ? 2 : 3) + text: "\u2702" + onClicked: { + if (!dividePop) + dividePop = divideComp.createObject(importWindow); + + dividePop.melPart = null; + dividePop.x = (importWindow.width - dividePop.width) / 2; + dividePop.y = NOO.factor() * 2; + dividePop.open(); + } + + font { + pixelSize: NOO.factor() * (NOO.isAndroid() ? 1.5 : 2.8) + family: "Nootka" + } + } + RectButton { - height: NOO.factor() * (NOO.isAndroid() ? 1.8 : 2.2) - font { pixelSize: NOO.factor() * (NOO.isAndroid() ? 1.5 : 2); family: "Nootka" } - text: "\u0193" - onClicked: { - if (!allChordsPop) - allChordsPop = allChordsComp.createObject(importWindow) - var p = parent.mapToItem(partList, 0, 0) - allChordsPop.melPart = modelData - allChordsPop.x = partList.width - allChordsPop.width - NOO.factor() * 4 - allChordsPop.y = p.y - allChordsPop.open() - } + height: NOO.factor() * (NOO.isAndroid() ? 2 : 3) + text: "\u0193" + onClicked: { + if (!allChordsPop) + allChordsPop = allChordsComp.createObject(importWindow); + + allChordsPop.melPart = null; + allChordsPop.x = (importWindow.width - allChordsPop.width) / 2; + allChordsPop.y = NOO.factor() * 2; + allChordsPop.open(); + } + + font { + pixelSize: NOO.factor() * (NOO.isAndroid() ? 1.5 : 2.8) + family: "Nootka" + } + } - } + } - } - ScrollBar.vertical: ScrollBar {} + } - Row { // Footer with 'Import' & 'Cancel' buttons - id: buttRow - y: parent.height - height - NOO.factor() / 2; x: (parent.width - width) / 2 - spacing: NOO.factor() * 2 - TiconButton { - y: NOO.factor() / 4 - pixmap: NOO.pix("exit") - text: NOO.TR("QShortcut", "Cancel") - color: Qt.tint(activPal.button, NOO.alpha("red", NOO.isAndroid() ? 40 : 0)) - onClicked: close() - } - TiconButton { - y: NOO.factor() / 4 - pixmap: NOO.pix("melody") - text: qsTr("Import") - color: Qt.tint(activPal.button, NOO.alpha("teal", NOO.isAndroid() ? 40 : 0)) - onClicked: { - melImport.emitImport() - close() + Component { + id: divideComp + + TpopupDialog { + property var melPart: null + + width: divMel.width + NOO.factor() * 2 + height: divMel.height + NOO.factor() * 7 + caption: melPart ? "" : qsTr("Transform all parts of the score") + onAccepted: { + if (melPart) + melPart.splitBarNr = divMel.divisionBy; + else + melImport.globalSplitNr = divMel.divisionBy; + } + + DivideMelody { + id: divMel + + divisionBy: parent.melPart ? dividePop.melPart.splitBarNr : melImport.globalSplitNr + } + } - } + } - Row { // Global 'Divide' action - anchors { left: parent.left; top: parent.top; topMargin: NOO.factor() / 4; leftMargin: NOO.factor() / 2 } - RectButton { - height: NOO.factor() * (NOO.isAndroid() ? 2 : 3) - font { pixelSize: NOO.factor() * (NOO.isAndroid() ? 1.5 : 2.8); family: "Nootka" } - text: "\u2702" - onClicked: { - if (!dividePop) - dividePop = divideComp.createObject(importWindow) - dividePop.melPart = null - dividePop.x = (importWindow.width - dividePop.width) / 2 - dividePop.y = NOO.factor() * 2 - dividePop.open() - } - } - RectButton { - height: NOO.factor() * (NOO.isAndroid() ? 2 : 3) - font { pixelSize: NOO.factor() * (NOO.isAndroid() ? 1.5 : 2.8); family: "Nootka" } - text: "\u0193" - onClicked: { - if (!allChordsPop) - allChordsPop = allChordsComp.createObject(importWindow) - allChordsPop.melPart = null - allChordsPop.x = (importWindow.width - allChordsPop.width) / 2 - allChordsPop.y = NOO.factor() * 2 - allChordsPop.open() + Component { + id: transComp + + TpopupDialog { + property var melPart: null + property alias initialKey: transpose.initialKey + + width: transpose.width + NOO.factor() * 2 + height: transpose.height + NOO.factor() * (melPart ? 5 : 7) + caption: melPart ? "" : qsTr("Transform all parts of the score") + onAboutToShow: { + transpose.toKey = false; + transpose.byInterval = false; + } + onAccepted: { + if (transpose.toKey || transpose.byInterval) { + if (transpose.toKey && melPart) + transPop.melPart.key = transpose.selectedKey; + + melImport.transpose(transpose.outShift, transpose.outScaleToRest, transpose.inInstrumentScale, transPop.melPart); + } + } + + Transpose { + id: transpose + } + } - } - } - } - - Component.onCompleted: { - melImport.importWindowReady() - if (GLOB.gotIt("ScoreImport", true)) - Qt.createComponent("qrc:/gotit/ImportInfo.qml").createObject(importWindow, { "remaindChecked": true }) - if (melImport.partsModel.length === 0) - busyComp.createObject(melImport) - partList.model = Qt.binding(function() { return melImport.partsModel }) - // It covers both cases: when model are ready before dialog and ready only after this onCompleted - } - - property var dividePop: null - Component { - id: divideComp - TpopupDialog { - property var melPart: null - width: divMel.width + NOO.factor() * 2 - height: divMel.height + NOO.factor() * 7 - caption: melPart ? "" : qsTr("Transform all parts of the score") - DivideMelody { - id: divMel - divisionBy: parent.melPart ? dividePop.melPart.splitBarNr : melImport.globalSplitNr - } - onAccepted: { - if (melPart) - melPart.splitBarNr = divMel.divisionBy - else - melImport.globalSplitNr = divMel.divisionBy - } + } - } - - property var transPop: null - Component { - id: transComp - TpopupDialog { - property var melPart: null - property alias initialKey: transpose.initialKey - width: transpose.width + NOO.factor() * 2 - height: transpose.height + NOO.factor() * (melPart ? 5 : 7) - caption: melPart ? "" : qsTr("Transform all parts of the score") - Transpose { - id: transpose - } - onAboutToShow: { - transpose.toKey = false - transpose.byInterval = false - } - onAccepted: { - if (transpose.toKey || transpose.byInterval) { - if (transpose.toKey && melPart) - transPop.melPart.key = transpose.selectedKey - melImport.transpose(transpose.outShift, transpose.outScaleToRest, transpose.inInstrumentScale, transPop.melPart) + + Component { + id: allChordsComp + + TpopupDialog { + property var melPart: null + + width: chCol.width + NOO.factor() * 3 + height: chCol.height + NOO.factor() * (melPart ? 5 : 7) + caption: melPart ? "" : qsTr("Transform all parts of the score") + onAccepted: { + if (melPart) { + if (chordNoteChB.checked) + melPart.selectNoteInChords(selChordNoteSpin.value, topBottCombo.currentIndex === 0); + else + melPart.arpeggiateChords(); + } else if (chordNoteChB.checked) { + melImport.selectNoteInChords(selChordNoteSpin.value, topBottCombo.currentIndex === 0); + } else { + melImport.arpeggiateChords(); + } + } + + Column { + id: chCol + + spacing: NOO.factor() + + TcheckBox { + id: chordNoteChB + + text: qsTr("in every chord") + onToggled: { + if (chordNoteChB.checked) + chordExplodeChB.checked = false; + + } + } + + Row { + spacing: NOO.factor() + x: NOO.factor() + enabled: chordNoteChB.checked + + Text { + text: qsTr("select", "[1st, 2nd, ...] note") + color: activPal.text + anchors.verticalCenter: parent.verticalCenter + } + + TspinBox { + id: selChordNoteSpin + + from: 1 + to: 10 + } + + Text { + text: qsTr("note", "select [1st, 2nd, ...] note [from the top/bottom]") + color: activPal.text + anchors.verticalCenter: parent.verticalCenter + } + + TcomboBox { + id: topBottCombo + + width: NOO.factor() * 12 + anchors.verticalCenter: parent.verticalCenter + model: [qsTr("from the top"), qsTr("from the bottom")] + } + + } + + TcheckBox { + id: chordExplodeChB + + text: qsTr("arpeggiate chords and insert all notes") + onToggled: { + if (chordExplodeChB.checked) + chordNoteChB.checked = false; + + } + } + + } + } - } + } - } - - property var allChordsPop - Component { - id: allChordsComp - TpopupDialog { - property var melPart: null - width: chCol.width + NOO.factor() * 3 - height: chCol.height + NOO.factor() * (melPart ? 5 : 7) - caption: melPart ? "" : qsTr("Transform all parts of the score") - Column { - id: chCol - spacing: NOO.factor() - TcheckBox { - id: chordNoteChB - text: qsTr("in every chord") - onToggled: { - if (chordNoteChB.checked) - chordExplodeChB.checked = false - } - } - Row { - spacing: NOO.factor(); x: NOO.factor() - enabled: chordNoteChB.checked - Text { - text: qsTr("select", "[1st, 2nd, ...] note") - color: activPal.text; anchors.verticalCenter: parent.verticalCenter - } - TspinBox { - id: selChordNoteSpin - from: 1; to: 10 - } - Text { - text: qsTr("note", "select [1st, 2nd, ...] note [from the top/bottom]") - color: activPal.text; anchors.verticalCenter: parent.verticalCenter } - TcomboBox { - id: topBottCombo - width: NOO.factor() * 12;anchors.verticalCenter: parent.verticalCenter - model: [ qsTr("from the top"), qsTr("from the bottom") ] - } - } - TcheckBox { - id: chordExplodeChB - text: qsTr("arpeggiate chords and insert all notes") - onToggled: { - if (chordExplodeChB.checked) - chordNoteChB.checked = false - } + + Component { + id: chordComp + + // preview of chord notes + MelodyPreview { + property var chordIt: null + + melody: chordIt ? chordIt.chord : null + showButtons: false + width: NOO.factor() * 24 + height: NOO.factor() * 26 + caption: chordIt && chordIt.selectSingle ? qsTr("Select one of the notes") : qsTr("Arpeggiate chord") + acceptButton.visible: chordIt && !chordIt.selectSingle + selectReadOnly: true + onReadOnlyNoteClicked: { + hi.parent = score.note(noteId); + chordIt.selected = noteId; + } + onAboutToShow: { + reload(); + hi.parent = score.note(chordIt.selected); + var p = parent.mapFromItem(chordIt, 0, chordIt.height / 2); + x = p.x - (p.x > parent.width / 2 ? width + NOO.factor() : -NOO.factor() * 2); + y = NOO.bound(NOO.factor(), p.y - height / 2, parent.height - height - NOO.factor()); + } + onAccepted: chordIt.arpeggiateChord() + + // selected chord note highlight + Rectangle { + id: hi + + parent: null + visible: parent != null + width: parent ? (parent.width - parent.alterWidth) * 1.5 : 0 + height: parent ? Math.min(12, parent.notePosY + 6) : 0 + x: parent ? -width * 0.25 : 0 + y: parent ? Math.min(parent.height - height, Math.max(0, parent.notePosY - height / 2)) : 0 + color: NOO.alpha(activPal.highlight, 75) + z: -1 + radius: width / 3 + } + + RectButton { + height: NOO.factor() * (NOO.isAndroid() ? 1.8 : 2.2) + visible: chordIt && chordIt.selectSingle + text: "\u0194" + onClicked: { + chordIt.setRhythm(); + reload(); + } + + anchors { + left: parent.left + top: parent.top + } + + font { + pixelSize: NOO.factor() * (NOO.isAndroid() ? 1.5 : 2) + family: "Nootka" + } + + ToolTip { + delay: 150 + timeout: 5000 + x: parent.width + NOO.factor() + y: (parent.height - height) / 2 + visible: parent.hovered + + contentItem: Text { + text: qsTr("Arpeggiate chord") + color: activPal.text + } + + 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.base + } + + } + + } + } - } - onAccepted: { - if (melPart) { - if (chordNoteChB.checked) - melPart.selectNoteInChords(selChordNoteSpin.value, topBottCombo.currentIndex === 0) - else - melPart.arpeggiateChords() - } else - if (chordNoteChB.checked) - melImport.selectNoteInChords(selChordNoteSpin.value, topBottCombo.currentIndex === 0) - else - melImport.arpeggiateChords() - } + } - } - - property var chordView: null - Component { - id: chordComp - MelodyPreview { // preview of chord notes - property var chordIt: null - melody: chordIt ? chordIt.chord : null - showButtons: false - width: NOO.factor() * 24; height: NOO.factor() * 26 - caption: chordIt && chordIt.selectSingle ? qsTr("Select one of the notes") : qsTr("Arpeggiate chord") - acceptButton.visible: chordIt && !chordIt.selectSingle - selectReadOnly: true - onReadOnlyNoteClicked: { - hi.parent = score.note(noteId) - chordIt.selected = noteId - } - onAboutToShow: { - reload() - hi.parent = score.note(chordIt.selected) - var p = parent.mapFromItem(chordIt, 0, chordIt.height / 2) - x = p.x - (p.x > parent.width / 2 ? width + NOO.factor() : - NOO.factor() * 2) - y = NOO.bound(NOO.factor(), p.y - height / 2, parent.height - height - NOO.factor()) - } - Rectangle { // selected chord note highlight - id: hi - parent: null - visible: parent != null - width: parent ? (parent.width - parent.alterWidth) * 1.5 : 0 - height: parent ? Math.min(12.0, parent.notePosY + 6.0) : 0 - x: parent ? -width * 0.25 : 0 - y: parent ? Math.min(parent.height - height, Math.max(0.0, parent.notePosY - height / 2.0)) : 0 - color: NOO.alpha(activPal.highlight, 75) - z: -1 - radius: width / 3.0 - } - RectButton { - height: NOO.factor() * (NOO.isAndroid() ? 1.8 : 2.2) - anchors { left: parent.left; top: parent.top } - visible: chordIt && chordIt.selectSingle - font { pixelSize: NOO.factor() * (NOO.isAndroid() ? 1.5 : 2); family: "Nootka" } - text: "\u0194" - onClicked: { - chordIt.setRhythm() - reload() - } - ToolTip { - delay: 150; timeout: 5000 - x: parent.width + NOO.factor(); y: (parent.height - height) / 2 - visible: parent.hovered - contentItem: Text { - text: qsTr("Arpeggiate chord") + + Component { + id: unsuppComp + + Text { + x: NOO.factor() + y: NOO.factor() * 1.2 color: activPal.text - } - 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.base } + style: Text.Sunken + styleColor: "red" + text: qsTr("This fragment contains elements of musical score which are not supported by Nootka!") } - } - onAccepted: chordIt.arpeggiateChord() - } - } - - Component { - id: unsuppComp - Text { - x: NOO.factor(); y: NOO.factor() * 1.2 - color: activPal.text; style: Text.Sunken; styleColor: "red" - text: qsTr("This fragment contains elements of musical score which are not supported by Nootka!") - } - } - - Component { - id: busyComp - BusyIndicator { - anchors.centerIn: parent - scale: Math.max(1, (parent.width / 10) / width) - running: melImport.partsModel.length === 0 + } - } - function showChord(chordIt) { - if (!chordView) - chordView = chordComp.createObject(importWindow) - chordView.chordIt = chordIt - chordView.open() - } + Component { + id: busyComp - onClosing: destroy() + BusyIndicator { + anchors.centerIn: parent + scale: Math.max(1, (parent.width / 10) / width) + running: melImport.partsModel.length === 0 + } + + } } diff --git a/src/qml/score/MelodyNameDialog.qml b/src/qml/score/MelodyNameDialog.qml index 6651ef5c256102fb64415de973c00a1d28fe5542..d527baa7bd121bc8d9533e78c8f53ef01b37316b 100644 --- a/src/qml/score/MelodyNameDialog.qml +++ b/src/qml/score/MelodyNameDialog.qml @@ -2,61 +2,109 @@ * 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 Nootka 1.0 -import "../" - - TpopupDialog { - id: melNamDial - - visible: true - width: NOO.factor() * 40; height: NOO.factor() * 12 - x: (parent.width - width) / 2 - y: NOO.isAndroid() ? NOO.factor() : (parent.height - height) / 2 - glowRect.radius: NOO.factor() - - rejectButton.text: NOO.TR("QPlatformTheme", "Discard") - acceptButton.text: NOO.TR("QShortcut", "Save") - acceptButton.pixmap: NOO.pix("save") - - Column { - anchors.centerIn: parent - spacing: NOO.factor() - Row { - anchors { right: parent.right; rightMargin: NOO.factor() / 2 } - spacing: NOO.factor() - Text { - anchors.verticalCenter: parent.verticalCenter - color: activPal.text - text: qsTr("Title") - } - TcomboEdit { - id: melodyTitle - maximumLength: 100 - model: mainObj.recentTitles() /**< @p mainObj is TmainScoreObject instance */ - width: melNamDial.width - NOO.factor() * 11 - } - } + id: melNamDial - Row { - anchors { right: parent.right; rightMargin: NOO.factor() / 2 } - spacing: NOO.factor() - Text { - anchors.verticalCenter: parent.verticalCenter - color: activPal.text - text: qsTr("Composer") - } - TcomboEdit { - id: composer - maximumLength: 100 - model: mainObj.recentComposers() - width: melNamDial.width - NOO.factor() * 11 - } + visible: true + width: NOO.factor() * 40 + height: NOO.factor() * 12 + x: (parent.width - width) / 2 + y: NOO.isAndroid() ? NOO.factor() : (parent.height - height) / 2 + glowRect.radius: NOO.factor() + rejectButton.text: NOO.TR("QPlatformTheme", "Discard") + acceptButton.text: NOO.TR("QShortcut", "Save") + acceptButton.pixmap: NOO.pix("save") + onAccepted: { + mainObj.saveMusicXml("", melodyTitle.editText, composer.editText); //fileName.text + destroy(300); } - /** + onRejected: destroy(300) + onOpened: SOUND.stopListen() + onClosed: SOUND.startListen() + + Column { + // Row { + // anchors.right: parent.right + // spacing: NOO.factor() + // Text { + // anchors.verticalCenter: parent.verticalCenter + // color: activPal.text + // text: NOO.TR("QFileDialog", "File") + // } + // Text { + // id: fileName + // anchors.verticalCenter: parent.verticalCenter + // font { pixelSize: NOO.factor(); bold: true } + // width: melNamDial.width - NOO.factor() * 14 + // horizontalAlignment: Text.AlignHCenter; elide: Text.ElideMiddle + // text: GLOB.lastXmlDir() + (NOO.isWindows() ? "\\" : "/") + composer.text + " - " + melodyTitle.text + ".musicxml" + // } + // TiconButton { + // pixmap: NOO.pix("open") + // onClicked: { + // var f = NOO.getXmlToSave(composer.text + " - " + melodyTitle.text) + // if (f !== "") + // fileName.text = f + // } + // } + // } + + anchors.centerIn: parent + spacing: NOO.factor() + + Row { + spacing: NOO.factor() + + anchors { + right: parent.right + rightMargin: NOO.factor() / 2 + } + + Text { + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + text: qsTr("Title") + } + + TcomboEdit { + id: melodyTitle + + maximumLength: 100 + model: mainObj.recentTitles() //*< @p mainObj is TmainScoreObject instance + width: melNamDial.width - NOO.factor() * 11 + } + + } + + Row { + spacing: NOO.factor() + + anchors { + right: parent.right + rightMargin: NOO.factor() / 2 + } + + Text { + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + text: qsTr("Composer") + } + + TcomboEdit { + id: composer + + maximumLength: 100 + model: mainObj.recentComposers() + width: melNamDial.width - NOO.factor() * 11 + } + + } + /** * FIXME * Code below displays fileName line with button to open file save dialog, * but when user selects some file name from that dialog it locks further title & composer changes for file name. @@ -66,39 +114,7 @@ TpopupDialog { * - name/composer QML dialog * - then save file dialog */ -// Row { -// anchors.right: parent.right -// spacing: NOO.factor() -// Text { -// anchors.verticalCenter: parent.verticalCenter -// color: activPal.text -// text: NOO.TR("QFileDialog", "File") -// } -// Text { -// id: fileName -// anchors.verticalCenter: parent.verticalCenter -// font { pixelSize: NOO.factor(); bold: true } -// width: melNamDial.width - NOO.factor() * 14 -// horizontalAlignment: Text.AlignHCenter; elide: Text.ElideMiddle -// text: GLOB.lastXmlDir() + (NOO.isWindows() ? "\\" : "/") + composer.text + " - " + melodyTitle.text + ".musicxml" -// } -// TiconButton { -// pixmap: NOO.pix("open") -// onClicked: { -// var f = NOO.getXmlToSave(composer.text + " - " + melodyTitle.text) -// if (f !== "") -// fileName.text = f -// } -// } -// } - } - - onAccepted: { - mainObj.saveMusicXml(/*fileName.text*/"", melodyTitle.editText, composer.editText) - destroy(300) - } - onRejected: destroy(300) - - onOpened: SOUND.stopListen() - onClosed: SOUND.startListen() + + } + } diff --git a/src/qml/score/MelodyPreview.qml b/src/qml/score/MelodyPreview.qml index 554b4ef7f52088d29f57d3cbd680bcd40c0ba343..fb0562f945e1d48d310a0b2d596a3a19204882e0 100644 --- a/src/qml/score/MelodyPreview.qml +++ b/src/qml/score/MelodyPreview.qml @@ -2,95 +2,129 @@ * 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 Nootka 1.0 +import QtQuick 2.12 import Score 1.0 -import "../" TpopupDialog { - id: popup - - property alias melody: melPrev.melody - property alias idText: nrText.text - property alias showButtons: buttons.visible - property alias selectReadOnly: melPrev.selectReadOnly - property alias score: sc.scoreObj - - /** + id: popup + + property alias melody: melPrev.melody + property alias idText: nrText.text + property alias showButtons: buttons.visible + property alias selectReadOnly: melPrev.selectReadOnly + property alias score: sc.scoreObj + /** * If set score @p height has priority until it reaches @p maxHeight then score uses scrolling. * When unset, @p height property has to be set */ - property real maxHeight: 0 + property real maxHeight: 0 - signal wantDivide() - signal wantTranspose() - signal readOnlyNoteClicked(var noteId) + signal wantDivide() + signal wantTranspose() + signal readOnlyNoteClicked(var noteId) - function reload() { melPrev.reload() } + function reload() { + melPrev.reload(); + } - height: maxHeight ? Math.min(maxHeight, header.height + sc.height + footer.height) : undefined + height: maxHeight ? Math.min(maxHeight, header.height + sc.height + footer.height) : undefined + bgColor: activPal.base + acceptButton.visible: false + rejectButton.text: NOO.TR("QShortcut", "Close") + caption: melPrev.title - bgColor: activPal.base - border { color: activPal.highlight; width: NOO.factor() / 4.0 } - acceptButton.visible: false - rejectButton.text: NOO.TR("QShortcut", "Close") + border { + color: activPal.highlight + width: NOO.factor() / 4 + } - caption: melPrev.title + TmelodyPreview { + id: melPrev - TmelodyPreview { - id: melPrev - width: parent.width; height: sc.height + width: parent.width + height: sc.height + score: sc.scoreObj + onReadOnlyNoteClicked: popup.readOnlyNoteClicked(noteId) - score: sc.scoreObj + Score { + id: sc - onReadOnlyNoteClicked: popup.readOnlyNoteClicked(noteId) + anchors.horizontalCenter: parent.horizontalCenter + bgRect.color: "transparent" + readOnly: true + width: popup.width - NOO.factor() + height: maxHeight ? Math.min(contentHeight, maxHeight - popup.footer.height) : popup.height - NOO.factor() * 4 - popup.header.height + firstStaff.scale: ((NOO.factor() * (clef === Tclef.PianoStaffClefs ? 18 : 15)) / firstStaff.linesCount) * scaleFactor + scoreObj.onStaffCreate: lastStaff.scale = firstStaff.scale + } - Score { - id: sc - anchors.horizontalCenter: parent.horizontalCenter - bgRect.color: "transparent" - readOnly: true - width: popup.width - NOO.factor() - height: maxHeight ? Math.min(contentHeight, maxHeight - popup.footer.height) : popup.height - NOO.factor() * 4 - popup.header.height - firstStaff.scale: ((NOO.factor() * (clef === Tclef.PianoStaffClefs ? 18 : 15)) / firstStaff.linesCount) * scaleFactor - scoreObj.onStaffCreate: lastStaff.scale = firstStaff.scale } - } - - Text { - text: melPrev.composer - x: parent.width - width - NOO.factor() / 2 - font { bold: true; pixelSize: NOO.factor() * 1.2 } - color: activPal.text - } - - Rectangle { - id: buttons - x: NOO.factor() / 2 - color: NOO.alpha(activPal.base, 200) - width: childrenRect.width; height: childrenRect.height - radius: NOO.factor() / 2 - Row { - z: 7 - spacing: NOO.factor() / 2 - Text { - id: nrText - font { bold: true; pixelSize: NOO.factor() * 2 } + + Text { + text: melPrev.composer + x: parent.width - width - NOO.factor() / 2 color: activPal.text - } - RectButton { - height: NOO.factor() * 2.2 - font { pixelSize: NOO.factor() * 2; family: "Nootka" } - text: "\u2702" - onClicked: wantDivide() - } - RectButton { - height: NOO.factor() * 2.2 - font { pixelSize: NOO.factor() * 2; family: "Nootka" } - text: "\u0192" - onClicked: wantTranspose() - } + + font { + bold: true + pixelSize: NOO.factor() * 1.2 + } + } - } + + Rectangle { + id: buttons + + x: NOO.factor() / 2 + color: NOO.alpha(activPal.base, 200) + width: childrenRect.width + height: childrenRect.height + radius: NOO.factor() / 2 + + Row { + z: 7 + spacing: NOO.factor() / 2 + + Text { + id: nrText + + color: activPal.text + + font { + bold: true + pixelSize: NOO.factor() * 2 + } + + } + + RectButton { + height: NOO.factor() * 2.2 + text: "\u2702" + onClicked: wantDivide() + + font { + pixelSize: NOO.factor() * 2 + family: "Nootka" + } + + } + + RectButton { + height: NOO.factor() * 2.2 + text: "\u0192" + onClicked: wantTranspose() + + font { + pixelSize: NOO.factor() * 2 + family: "Nootka" + } + + } + + } + + } + } diff --git a/src/qml/score/Meter.qml b/src/qml/score/Meter.qml index 0e40ced21eb1fc274195c7acd3c0d8d7c13953e3..01e18cf098bc5dd8fd97ab7c882f300c9fd4000f 100644 --- a/src/qml/score/Meter.qml +++ b/src/qml/score/Meter.qml @@ -2,50 +2,62 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 +import Nootka.Music import QtQuick 2.12 import QtQuick.Controls 2.12 - -import Nootka 1.0 import Score 1.0 -import Nootka.Music Text { - id: meter - - Connections { - target: score - onMeterChanged: text = NOO.meter(score.meter).symbol() - } - - font { family: "Scorek"; pixelSize: 8 } - color: meterArea.containsMouse && scoreObj.editMode ? GLOB.noteCursorColor : activPal.text - text: NOO.meter(score.meter).symbol() - y: score.upperLine - 11 - x: (staff0.keySignItem ? staff0.keySignItem.x + staff0.keySignItem.width : staff0.clef.x + staff0.clef.width) + 1.0 - - Loader { sourceComponent: score.clef === Tclef.PianoStaffClefs ? lowerMeter : null } - Component { - id: lowerMeter - Text { - font: meter.font - color: meter.color - text: meter.text - y: 22 + id: meter + + color: meterArea.containsMouse && scoreObj.editMode ? GLOB.noteCursorColor : activPal.text + text: NOO.meter(score.meter).symbol() + y: score.upperLine - 11 + x: (staff0.keySignItem ? staff0.keySignItem.x + staff0.keySignItem.width : staff0.clef.x + staff0.clef.width) + 1 + + Connections { + target: score + onMeterChanged: text = NOO.meter(score.meter).symbol() } - } - - MouseArea { - id: meterArea - y: 6 - width: parent.width; height: parent.height + (score.clef === Tclef.PianoStaffClefs ? 2 : -20) - enabled: !score.readOnly && scoreObj.editMode - hoverEnabled: true - property Drawer meterDrawer - onClicked: { - if (meterDrawer) - meterDrawer.open() - else - meterDrawer = Qt.createComponent("qrc:/score/MeterDrawer.qml").createObject(nootkaWindow.contentItem) + + font { + family: "Scorek" + pixelSize: 8 + } + + Loader { + sourceComponent: score.clef === Tclef.PianoStaffClefs ? lowerMeter : null } - } + + Component { + id: lowerMeter + + Text { + font: meter.font + color: meter.color + text: meter.text + y: 22 + } + + } + + MouseArea { + id: meterArea + + property Drawer meterDrawer + + y: 6 + width: parent.width + height: parent.height + (score.clef === Tclef.PianoStaffClefs ? 2 : -20) + enabled: !score.readOnly && scoreObj.editMode + hoverEnabled: true + onClicked: { + if (meterDrawer) + meterDrawer.open(); + else + meterDrawer = Qt.createComponent("qrc:/score/MeterDrawer.qml").createObject(nootkaWindow.contentItem); + } + } + } diff --git a/src/qml/score/MeterDrawer.qml b/src/qml/score/MeterDrawer.qml index 2e8ac266394d42c71a551acb259fadfc6b522a7a..7ff53b09eaa81e39199eb7e60efbbe0e7d0016a5 100644 --- a/src/qml/score/MeterDrawer.qml +++ b/src/qml/score/MeterDrawer.qml @@ -2,52 +2,71 @@ * 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 Nootka 1.0 import Score 1.0 -import "../" -Drawer { // meter menu - visible: true - width: nootkaWindow.width / 5; height: nootkaWindow.height - background: GlowRect { color: activPal.window; cornerRadius: NOO.factor() / 2; radius: 0 } - - // private - property var colorArr: [ 0, 1, 1, 0 ] - - GridView { - id: meterGrid - anchors.fill: parent - clip: true - contentHeight: childrenRect.height - cellHeight: NOO.factor() * 5 - cellWidth: parent.width / 2 - model: 12 - delegate: Rectangle { - height: NOO.factor() * 5 - 2 - width: parent.width / 2 - 2 - color: score.scoreObj.meter === Math.pow(2, index) ? activPal.highlight : - (area.containsMouse ? Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 50)) : (colorArr[index % 4] === 1 ? activPal.alternateBase : activPal.base)) - Text { - id: buttText - anchors.horizontalCenter: parent.horizontalCenter - y: -NOO.factor() * 4.5 - font { family: "Scorek"; pixelSize: NOO.factor() * 4 } - text: NOO.meter(Math.pow(2, index)).symbol() - color: score.scoreObj.meter === Math.pow(2, index) ? activPal.highlightedText : activPal.text - } - MouseArea { +// meter menu +Drawer { + // private + property var colorArr: [0, 1, 1, 0] + + visible: true + width: nootkaWindow.width / 5 + height: nootkaWindow.height + + GridView { + id: meterGrid + anchors.fill: parent - id: area - hoverEnabled: true - onClicked: { - score.scoreObj.setMeter(Math.pow(2, index)) - meter.text = buttText.text - close() + clip: true + contentHeight: childrenRect.height + cellHeight: NOO.factor() * 5 + cellWidth: parent.width / 2 + model: 12 + + delegate: Rectangle { + height: NOO.factor() * 5 - 2 + width: parent.width / 2 - 2 + color: score.scoreObj.meter === Math.pow(2, index) ? activPal.highlight : (area.containsMouse ? Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 50)) : (colorArr[index % 4] === 1 ? activPal.alternateBase : activPal.base)) + + Text { + id: buttText + + anchors.horizontalCenter: parent.horizontalCenter + y: -NOO.factor() * 4.5 + text: NOO.meter(Math.pow(2, index)).symbol() + color: score.scoreObj.meter === Math.pow(2, index) ? activPal.highlightedText : activPal.text + + font { + family: "Scorek" + pixelSize: NOO.factor() * 4 + } + + } + + MouseArea { + id: area + + anchors.fill: parent + hoverEnabled: true + onClicked: { + score.scoreObj.setMeter(Math.pow(2, index)); + meter.text = buttText.text; + close(); + } + } + } - } + } - } + + background: GlowRect { + color: activPal.window + cornerRadius: NOO.factor() / 2 + radius: 0 + } + } diff --git a/src/qml/score/NoteAdd.qml b/src/qml/score/NoteAdd.qml index f7a4e19c19d8058e3a0eed80e9e91edc2c4f5d60..0ee9c2972250846bec119aa7d400894b2cc0c5e6 100644 --- a/src/qml/score/NoteAdd.qml +++ b/src/qml/score/NoteAdd.qml @@ -2,57 +2,80 @@ * Copyright (C) 2017-2019 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 +import QtQuick 2.12 import Score 1.0 - /** * Control displaying prompt for adding note or note cursor when hovered/pressed */ TaddNoteItem { - id: noteAdd - - property alias hiTimer: hiTimer - - scoreObject: score.scoreObj - parent: score.lastStaff - height: parent ? parent.height : 0 - width: 4 - x: scoreObj.lastNote && !score.readOnly ? scoreObj.lastNote.rightX + 1.5 : score.firstStaff.firstNoteX - z: 11 - visible: scoreObj.allowAdding && scoreObj.editMode - - Behavior on x { enabled: GLOB.useAnimations; SpringAnimation { spring: 3; damping: 0.2; duration: 300 }} - - // private - property bool blink: true - - Rectangle { // highlight - visible: currentNote === null && !cursor.visible && (blink || !hiTimer.running) - width: 6; height: 12; x: -1; y: 14 - color: NOO.alpha(activPal.highlight, 75) - radius: 2 - } - - Timer { - id: hiTimer - interval: 500; repeat: true - running: SOUND.listening && !SOUND.tunerMode - onTriggered: blink = !blink - } - - Text { - id: note - visible: !active && !score.readOnly - font { family: "nootka"; pixelSize: 8 } - color: NOO.alpha(GLOB.noteCursorColor, 200) - x: (4 - width) / 2 - y: 15 - text: NOO.rhythmText(scoreObj.workRhythm) - } - - NoteCursor { id: cursor; yPos: noteAdd.yPos; headText: scoreObj.workRtmText } + id: noteAdd + + property alias hiTimer: hiTimer + // private + property bool blink: true + + scoreObject: score.scoreObj + parent: score.lastStaff + height: parent ? parent.height : 0 + width: 4 + x: scoreObj.lastNote && !score.readOnly ? scoreObj.lastNote.rightX + 1.5 : score.firstStaff.firstNoteX + z: 11 + visible: scoreObj.allowAdding && scoreObj.editMode + + // highlight + Rectangle { + visible: currentNote === null && !cursor.visible && (blink || !hiTimer.running) + width: 6 + height: 12 + x: -1 + y: 14 + color: NOO.alpha(activPal.highlight, 75) + radius: 2 + } + + Timer { + id: hiTimer + + interval: 500 + repeat: true + running: SOUND.listening && !SOUND.tunerMode + onTriggered: blink = !blink + } + + Text { + id: note + + visible: !active && !score.readOnly + color: NOO.alpha(GLOB.noteCursorColor, 200) + x: (4 - width) / 2 + y: 15 + text: NOO.rhythmText(scoreObj.workRhythm) + + font { + family: "nootka" + pixelSize: 8 + } + + } + + NoteCursor { + id: cursor + + yPos: noteAdd.yPos + headText: scoreObj.workRtmText + } + + Behavior on x { + enabled: GLOB.useAnimations + + SpringAnimation { + spring: 3 + damping: 0.2 + duration: 300 + } + + } } diff --git a/src/qml/score/NoteCursor.qml b/src/qml/score/NoteCursor.qml index 1e89163f19354f3de69027bef0504eac98f7e5ac..5d7e311ddc886e1c3492a95e69990069228decc9 100644 --- a/src/qml/score/NoteCursor.qml +++ b/src/qml/score/NoteCursor.qml @@ -2,92 +2,134 @@ * Copyright (C) 2017-2018 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 -import Score 1.0 import Nootka.Music +import QtQuick 2.12 +import Score 1.0 Item { - id: noteCursor - - height: parent ? parent.height : 0 - width: parent ? parent.width : 0 - - property string headText: parent && (score.singleNote || scoreObj.workRtmValue) ? scoreObj.activeRtmText() : "\uf4be" - property color color: GLOB.noteCursorColor - property real yPos: scoreObj.activeYpos - - visible: yPos > 0 && (GLOB.singleNote || scoreObj.editMode) - - Rectangle { // highlight - width: parent.width + 1 - height: parent.height - x: -1 - color: NOO.alpha(noteCursor.color, 26) - z: -10; radius: width / 8 - } - - Text { - id: head - scale: 1.2 - font { family: "Scorek"; pixelSize: 7 } - text: headText - y: yPos - 15 - color: noteCursor.color - x: score.singleNote ? 1.5 : 0 - - Text { - id: alter - font { family: "Scorek"; pixelSize: 7 } + id: noteCursor + + property string headText: parent && (score.singleNote || scoreObj.workRtmValue) ? scoreObj.activeRtmText() : "\uf4be" + property color color: GLOB.noteCursorColor + property real yPos: scoreObj.activeYpos + + height: parent ? parent.height : 0 + width: parent ? parent.width : 0 + visible: yPos > 0 && (GLOB.singleNote || scoreObj.editMode) + + // highlight + Rectangle { + width: parent.width + 1 + height: parent.height + x: -1 + color: NOO.alpha(noteCursor.color, 26) + z: -10 + radius: width / 8 + } + + Text { + id: head + + scale: 1.2 + text: headText + y: yPos - 15 color: noteCursor.color - x: -width - 0.1 - text: score.alterText + x: score.singleNote ? 1.5 : 0 + + font { + family: "Scorek" + pixelSize: 7 + } + Text { - font { family: "Scorek"; pixelSize: 7 } - color: activPal.shadow - x: 0.25; y: 0.25; z: -1 - text: parent.text - opacity: 0.6 + id: alter + + color: noteCursor.color + x: -width - 0.1 + text: score.alterText + + font { + family: "Scorek" + pixelSize: 7 + } + + Text { + color: activPal.shadow + x: 0.25 + y: 0.25 + z: -1 + text: parent.text + opacity: 0.6 + + font { + family: "Scorek" + pixelSize: 7 + } + + } + } - } - - Text { - font { family: "Scorek"; pixelSize: 7 } - x: 0.25; y: 0.25; z: -1 - color: activPal.shadow - text: head.text - opacity: 0.6 - } - } - - Repeater { // upper lines - model: (score.upperLine - 2) / 2 - AddLine { - y: 2 * (index + 1) - 0.1 - visible: yPos > 0 && index >= Math.floor((yPos - 1) / 2) - } - } - Repeater { // upper staff mid lines - model: score.clef === Tclef.PianoStaffClefs ? 2 : 0 - AddLine { - y: score.upperLine + 10 + 2 * index - 0.1 - visible: yPos >= y && yPos < score.upperLine + 14 - } - } - Repeater { // lower staff mid lines - model: score.clef === Tclef.PianoStaffClefs ? 4 : 0 - AddLine { - y: score.upperLine + 14 + 2 * index - 0.1 - visible: yPos <= y + 0.1 && yPos > score.upperLine + 13 && yPos < score.upperLine + 24 - } - } - Repeater { // lower lines - model: Math.max(0, (score.firstStaff.height - score.upperLine - (score.clef === Tclef.PianoStaffClefs ? 28 : 12)) / 2) - AddLine { - y: score.upperLine + (score.clef === Tclef.PianoStaffClefs ? 30 : 10) + 2 * index - 0.1 - visible: score.upperLine + (score.clef === Tclef.PianoStaffClefs ? 30 : 10) + index * 2 <= yPos - } - } + + Text { + x: 0.25 + y: 0.25 + z: -1 + color: activPal.shadow + text: head.text + opacity: 0.6 + + font { + family: "Scorek" + pixelSize: 7 + } + + } + + } + + // upper lines + Repeater { + model: (score.upperLine - 2) / 2 + + AddLine { + y: 2 * (index + 1) - 0.1 + visible: yPos > 0 && index >= Math.floor((yPos - 1) / 2) + } + + } + + // upper staff mid lines + Repeater { + model: score.clef === Tclef.PianoStaffClefs ? 2 : 0 + + AddLine { + y: score.upperLine + 10 + 2 * index - 0.1 + visible: yPos >= y && yPos < score.upperLine + 14 + } + + } + + // lower staff mid lines + Repeater { + model: score.clef === Tclef.PianoStaffClefs ? 4 : 0 + + AddLine { + y: score.upperLine + 14 + 2 * index - 0.1 + visible: yPos <= y + 0.1 && yPos > score.upperLine + 13 && yPos < score.upperLine + 24 + } + + } + + // lower lines + Repeater { + model: Math.max(0, (score.firstStaff.height - score.upperLine - (score.clef === Tclef.PianoStaffClefs ? 28 : 12)) / 2) + + AddLine { + y: score.upperLine + (score.clef === Tclef.PianoStaffClefs ? 30 : 10) + 2 * index - 0.1 + visible: score.upperLine + (score.clef === Tclef.PianoStaffClefs ? 30 : 10) + index * 2 <= yPos + } + + } } diff --git a/src/qml/score/NotePrompt.qml b/src/qml/score/NotePrompt.qml index 3f6c8d1741636a7a91e69cd9f4a26cc4d1875e6e..196c6f18679b81ee385c125be9b0d3d9bf9da0e7 100644 --- a/src/qml/score/NotePrompt.qml +++ b/src/qml/score/NotePrompt.qml @@ -2,17 +2,21 @@ * Copyright (C) 2018 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 +import QtQuick 2.12 import Score 1.0 - Text { - parent: scoreObj.note(0) - text: "n" - font { pixelSize: parent.width * 2.2; family: "Nootka" } - color: NOO.alpha(GLOB.isExam ? GLOB.correctColor : GLOB.noteCursorColor, 50) - x: (parent.width - width) / 2 - 0.5; y: score.upperLine - 1.6 - visible: !scoreObj.readOnly && parent.notePosY === 0 && !(score.cursor && score.cursor.parent) + parent: scoreObj.note(0) + text: "n" + color: NOO.alpha(GLOB.isExam ? GLOB.correctColor : GLOB.noteCursorColor, 50) + x: (parent.width - width) / 2 - 0.5 + y: score.upperLine - 1.6 + visible: !scoreObj.readOnly && parent.notePosY === 0 && !(score.cursor && score.cursor.parent) + + font { + pixelSize: parent.width * 2.2 + family: "Nootka" + } + } diff --git a/src/qml/score/Scordature.qml b/src/qml/score/Scordature.qml index 7ba083b80d2a35791474d96dff027136725c4dec..541b57a748df3736794570090565cc34454c3b69 100644 --- a/src/qml/score/Scordature.qml +++ b/src/qml/score/Scordature.qml @@ -2,54 +2,71 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 +import QtQuick 2.12 import Score 1.0 - Grid { + property real realHeight: Math.floor(scordModel.count / columns) * 12 * scale - property real realHeight: Math.floor(scordModel.count / columns) * 12 * scale - - y: upperLine + 14 + (score.clef === Tclef.PianoStaffClefs ? 18 : 0) - x: 0.5 - spacing: 0.5 - scale: columns > 1 ? 0.2 : (score.clef === Tclef.PianoStaffClefs ? 0.35 : 0.3) - transformOrigin: Item.TopLeft - columns: GLOB.tuning.changedStrings() > 3 ? 2 : 1 - visible: score.clef !== Tclef.NoClef - - Repeater { - model: ListModel { id: scordModel } - Row { - height: 12 - Text { - text: strNr - font { pixelSize: 12; family: "Nootka" } - anchors.verticalCenter: parent.verticalCenter - } - Text { - topPadding: 3.5 - text: "=" + name - font { pixelSize: 8; family: "Scorek" } - anchors.verticalCenter: parent.verticalCenter - } + y: upperLine + 14 + (score.clef === Tclef.PianoStaffClefs ? 18 : 0) + x: 0.5 + spacing: 0.5 + scale: columns > 1 ? 0.2 : (score.clef === Tclef.PianoStaffClefs ? 0.35 : 0.3) + transformOrigin: Item.TopLeft + columns: GLOB.tuning.changedStrings() > 3 ? 2 : 1 + visible: score.clef !== Tclef.NoClef + Component.onCompleted: { + for (var s = 0; s < 6; ++s) { + if (GLOB.tuning.otherThanStd(s + 1)) + scordModel.append({ + "strNr": s + 1, + "name": GLOB.tuning.stringName(s + 1) + }); + + } } - } - Component.onCompleted: { - for (var s = 0; s < 6; ++s) { - if (GLOB.tuning.otherThanStd(s + 1)) - scordModel.append({ "strNr": s + 1, "name": GLOB.tuning.stringName(s + 1) }) + Repeater { + Row { + height: 12 + + Text { + text: strNr + anchors.verticalCenter: parent.verticalCenter + + font { + pixelSize: 12 + family: "Nootka" + } + + } + + Text { + topPadding: 3.5 + text: "=" + name + anchors.verticalCenter: parent.verticalCenter + + font { + pixelSize: 8 + family: "Scorek" + } + + } + + } + + model: ListModel { + id: scordModel + } + } - } - Connections { - target: GLOB - onNoteNameStyleChanged: { - for (var s = 0; s < scordModel.count; ++s) - scordModel.get(s).name = GLOB.tuning.stringName(scordModel.get(s).strNr) + Connections { + target: GLOB + onNoteNameStyleChanged: { + for (var s = 0; s < scordModel.count; ++s) scordModel.get(s).name = GLOB.tuning.stringName(scordModel.get(s).strNr) + } } - } + } diff --git a/src/qml/score/Score.qml b/src/qml/score/Score.qml index c901be79d74866de4c7318b7e89d7cab72b02fa4..138e444ce752cebcf8c0ae787dc7944efd5393e1 100644 --- a/src/qml/score/Score.qml +++ b/src/qml/score/Score.qml @@ -2,143 +2,177 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 - -import Nootka 1.0 import Score 1.0 - Flickable { - id: score - - property alias scoreObj: scoreObj - property alias scale: staff0.scale - property alias firstStaff: staff0 - property Staff lastStaff: staff0 - property alias clef: scoreObj.clefType - property alias upperLine: staff0.upperLine - property alias meter: scoreObj.meter - property alias bgColor: bgRect.color - property alias enableKeySign: scoreObj.keySignatureEnabled - property alias keySignature: scoreObj.keySignature - property bool enableDoubleAccids: false - property alias workRhythm: scoreObj.workRhythm - property alias scaleFactor: scoreObj.scaleFactor - property alias notesCount: scoreObj.notesCount - property alias currentNote: scoreObj.selectedItem - property alias note: scoreObj.selectedNote - property alias readOnly: scoreObj.readOnly - property alias singleNote: scoreObj.singleNote - property alias bgRect: bgRect - property alias alterText: scoreObj.alterText - property alias editText: editText - - property alias insertNoteAct: scoreObj.insertNoteAct - property alias deleteNoteAct: scoreObj.deleteNoteAct - property alias clearScoreAct: scoreObj.clearScoreAct - - // private - property var staves: [ staff0 ] - property var noteAdd: null - property var delControl: null - property var cursor: null - property var scoreToobox: null - - clip: true - boundsBehavior: Flickable.StopAtBounds - width: parent.width - - contentWidth: score.width - - ScrollBar.vertical: ScrollBar { active: false; visible: active } - -// maximumFlickVelocity: 1000 // 2500 by default - - TscoreObject { - id: scoreObj - width: score.width / scale - - enableDoubleAccidentals: score.enableDoubleAccids - - onClicked: currentNote = scoreObj.activeNote - - onStaffCreate: { - staves.push(Qt.createComponent("qrc:/score/Staff.qml").createObject(score.contentItem)) - score.lastStaff = staves[staves.length - 1] + // maximumFlickVelocity: 1000 // 2500 by default + + id: score + + property alias scoreObj: scoreObj + property alias scale: staff0.scale + property alias firstStaff: staff0 + property Staff lastStaff: staff0 + property alias clef: scoreObj.clefType + property alias upperLine: staff0.upperLine + property alias meter: scoreObj.meter + property alias bgColor: bgRect.color + property alias enableKeySign: scoreObj.keySignatureEnabled + property alias keySignature: scoreObj.keySignature + property bool enableDoubleAccids: false + property alias workRhythm: scoreObj.workRhythm + property alias scaleFactor: scoreObj.scaleFactor + property alias notesCount: scoreObj.notesCount + property alias currentNote: scoreObj.selectedItem + property alias note: scoreObj.selectedNote + property alias readOnly: scoreObj.readOnly + property alias singleNote: scoreObj.singleNote + property alias bgRect: bgRect + property alias alterText: scoreObj.alterText + property alias editText: editText + property alias insertNoteAct: scoreObj.insertNoteAct + property alias deleteNoteAct: scoreObj.deleteNoteAct + property alias clearScoreAct: scoreObj.clearScoreAct + // private + property var staves: [staff0] + property var noteAdd: null + property var delControl: null + property var cursor: null + property var scoreToobox: null + + function ensureVisible(yy, hh) { + if (contentY >= yy) + contentY = yy; + else if (contentY + height <= yy + hh) + contentY = yy + hh - height; + } + + function addNote(n) { + scoreObj.addNote(n, true); + } + + function setNote(noteItem, note) { + scoreObj.setNote(noteItem, note); + } + + function clearScore() { + scoreObj.clearScore(); + } + + function deleteLast() { + scoreObj.deleteLastNote(); + } + + clip: true + boundsBehavior: Flickable.StopAtBounds + width: parent.width + contentWidth: score.width + onCurrentNoteChanged: { + if (currentNote && staves.length > 1) + ensureVisible(currentNote.staffItem.y, currentNote.staffItem.height * scale); + + } + + TscoreObject { + id: scoreObj + + width: score.width / scale + enableDoubleAccidentals: score.enableDoubleAccids + onClicked: currentNote = scoreObj.activeNote + onStaffCreate: { + staves.push(Qt.createComponent("qrc:/score/Staff.qml").createObject(score.contentItem)); + score.lastStaff = staves[staves.length - 1]; + } + onStavesHeightChanged: score.contentHeight = Math.max(stavesHeight, score.height) + onStaffDestroying: { + staves.splice(staffNr, 1); + lastStaff = staves[staves.length - 1]; + } + onNoteWasAdded: { + if (staves.length > 1) + ensureVisible(lastNote.staffItem.y, lastNote.staffItem.height * scale); + + } + onAllowAddingChanged: { + if (allowAdding) { + if (!delControl) + delControl = Qt.createComponent("qrc:/score/DelControl.qml").createObject(contentItem); + + if (!noteAdd) + noteAdd = Qt.createComponent("qrc:/score/NoteAdd.qml").createObject(contentItem); + + if (!scoreToobox) + scoreToobox = Qt.createComponent("qrc:/score/ScoreToolbox.qml").createObject(parent); + + } + } + onActiveNoteChanged: { + if (!cursor) { + cursor = Qt.createComponent("qrc:/score/ScoreCursor.qml").createObject(contentItem); + cursor.parent = Qt.binding(function() { + return scoreObj.activeNote; + }); + } + if (!scoreToobox && !readOnly) + scoreToobox = Qt.createComponent("qrc:/score/ScoreToolbox.qml").createObject(parent); + + } + onScoreWasCleared: ensureVisible(0, 0) + } + + // entire score background + Rectangle { + id: bgRect + + parent: score + z: -1 + width: score.width + height: score.height + color: NOO.alpha(scoreObj.bgColor, 230) } - onStavesHeightChanged: score.contentHeight = Math.max(stavesHeight, score.height) + // first staff (always exists) + Staff { + id: staff0 - onStaffDestroying: { staves.splice(staffNr, 1); lastStaff = staves[staves.length - 1] } + meter: Meter { + parent: staff0 + } - onNoteWasAdded: { - if (staves.length > 1) - ensureVisible(lastNote.staffItem.y, lastNote.staffItem.height * scale) } - onAllowAddingChanged: { - if (allowAdding) { - if (!delControl) - delControl = Qt.createComponent("qrc:/score/DelControl.qml").createObject(contentItem) - if (!noteAdd) - noteAdd = Qt.createComponent("qrc:/score/NoteAdd.qml").createObject(contentItem) - if (!scoreToobox) - scoreToobox = Qt.createComponent("qrc:/score/ScoreToolbox.qml").createObject(parent) - } + // edit mode symbol + Text { + id: editText + + opacity: scoreObj.editMode && !singleNote ? 1 : 0 + x: NOO.factor() * 3 + y: score.contentY + NOO.factor() / 2 + text: "\u0080" + color: NOO.alpha(GLOB.noteCursorColor, 200) + + font { + family: "Nootka" + pixelSize: NOO.factor() * 2 + } + + Behavior on opacity { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 500 + } + + } + } - onActiveNoteChanged: { - if (!cursor) { - cursor = Qt.createComponent("qrc:/score/ScoreCursor.qml").createObject(contentItem) - cursor.parent = Qt.binding(function() { return scoreObj.activeNote }) - } - if (!scoreToobox && !readOnly) - scoreToobox = Qt.createComponent("qrc:/score/ScoreToolbox.qml").createObject(parent) + ScrollBar.vertical: ScrollBar { + active: false + visible: active } - onScoreWasCleared: ensureVisible(0, 0) - } - - onCurrentNoteChanged: { - if (currentNote && staves.length > 1) - ensureVisible(currentNote.staffItem.y, currentNote.staffItem.height * scale) - } - - Rectangle { // entire score background - id: bgRect - parent: score - z: -1 - width: score.width; height: score.height - color: NOO.alpha(scoreObj.bgColor, 230) - } - - Staff { // first staff (always exists) - id: staff0 - meter: Meter { parent: staff0 } - } - - Text { // edit mode symbol - id: editText - opacity: scoreObj.editMode && !singleNote ? 1 : 0 - Behavior on opacity { enabled: GLOB.useAnimations; NumberAnimation { duration: 500 }} - x: NOO.factor() * 3; y: score.contentY + NOO.factor() / 2 - text: "\u0080"; font { family: "Nootka"; pixelSize: NOO.factor() * 2 } - color: NOO.alpha(GLOB.noteCursorColor, 200) - } - - function ensureVisible(yy, hh) { - if (contentY >= yy) - contentY = yy - else if (contentY + height <= yy + hh) - contentY = yy + hh - height - } - - function addNote(n) { scoreObj.addNote(n ,true) } - - function setNote(noteItem, note) { scoreObj.setNote(noteItem, note) } - - function clearScore() { scoreObj.clearScore() } - - function deleteLast() { scoreObj.deleteLastNote() } } diff --git a/src/qml/score/ScoreCursor.qml b/src/qml/score/ScoreCursor.qml index 73642d28c0c2b86b6e9769b44c73e2665289ea36..910bc957faee96effca6c86744af0ae6ab5cd117 100644 --- a/src/qml/score/ScoreCursor.qml +++ b/src/qml/score/ScoreCursor.qml @@ -3,22 +3,20 @@ * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ import QtQuick 2.12 - import Score 1.0 - NoteCursor { - width: parent ? parent.width - (scoreObj.singleNote ? 0 : parent.alterWidth) : 0 - - // private - property bool allow: true - - visible: yPos > 0 && allow && (scoreObj.singleNote || scoreObj.editMode) - - Connections { // hide cursor after click on a note to show what was selected - target: scoreObj - onClicked: allow = false - onActiveYposChanged: allow = scoreObj.activeYpos > 0 - } + // private + property bool allow: true + + width: parent ? parent.width - (scoreObj.singleNote ? 0 : parent.alterWidth) : 0 + visible: yPos > 0 && allow && (scoreObj.singleNote || scoreObj.editMode) + + // hide cursor after click on a note to show what was selected + Connections { + target: scoreObj + onClicked: allow = false + onActiveYposChanged: allow = scoreObj.activeYpos > 0 + } } diff --git a/src/qml/score/ScoreToolbox.qml b/src/qml/score/ScoreToolbox.qml index 7432d4c0e6f7b105f848f92d2d339a2513777924..a767b3a1fe9ebfa05183e23aef6cba50f10d806d 100644 --- a/src/qml/score/ScoreToolbox.qml +++ b/src/qml/score/ScoreToolbox.qml @@ -2,191 +2,274 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 -import Score 1.0 import Nootka.Music +import QtQuick 2.12 +import Score 1.0 ControlBase { - id: toolbox - - x: show ? 2 : -width - NOO.factor() - y: score.singleNote || score.meter === Tmeter.NoMeter ? (score.height - height) / 2 : - (NOO.isAndroid() ? (nootkaWindow.height - height) / 2 : NOO.factor() / 2) - z: 1010 // above mobile menu button - visible: !scoreObj.touched && loader.active - - active: !score.readOnly && (scoreObj.activeNote || (score.noteAdd && score.noteAdd.active)) - - factor: NOO.isAndroid() ? NOO.shortScreenSide() * 0.04 : NOO.factor() * 1.2 - - property string rhythmText: NOO.rhythmText(scoreObj.workRhythm) - property bool triplet: false - property bool tie: scoreObj.selectedItem && scoreObj.selectedItem.hasTie - - // Accidentals - property int selectedId: idArray[scoreObj.cursorAlter + 2] - property string text: selectedId > -1 ? accidGlyphs[selectedId] : "" - property int alter: accidArray[selectedId + 1] - readonly property var accidGlyphs: [ "\ue264", "\ue260", "\ue262", "\ue263" ] - readonly property var accidArray: [ 0, -2, -1, 1, 2 ] - readonly property var idArray: [ 0, 1, -1, 2, 3 ] - readonly property var rtmActions: [ scoreObj.wholeNoteAct, scoreObj.halfNoteAct, - scoreObj.quarterNoteAct, scoreObj.eighthNoteAct, scoreObj.sixteenthNoteAct ] - readonly property var accidTips: [ - qsTr("<b>double flat</b> - lowers a note by two semitones (whole tone).<br>On the guitar it is two frets down."), - qsTr("<b>flat</b> - lowers a note by a half tone (semitone).<br>On the guitar it is one fret down."), - qsTr("<b>sharp</b> - raises a note by a half tone (semitone).<br>On the guitar it is one fret up."), - qsTr("<b>double sharp</b> - raises a note by two semitones (whole tone).<br>On the guitar it is two frets up."), - ] - - Component { - id: ctrlButtonComp - ControlButton { - property int rhythm: 1 - property bool rest: false - factor: toolbox.factor * 0.9 - yOffset: factor * 0.5 - font { family: "nootka"; pixelSize: factor * 2 } - text: NOO.rhythmText(NOO.rhythm(rhythm, rest, false, false)) - selected: rhythm === scoreObj.workRtmValue && rest === scoreObj.workRtmRest - onEntered: hideTimer.stop() - onExited: hideTimer.restart() - } - } - - component: Component { - id: contentComp - Column { - - Grid { - columns: score.meter === Tmeter.NoMeter ? 1 : 2 - anchors.horizontalCenter: parent.horizontalCenter - Repeater { - model: 4 - ControlButton { + id: toolbox + + property string rhythmText: NOO.rhythmText(scoreObj.workRhythm) + property bool triplet: false + property bool tie: scoreObj.selectedItem && scoreObj.selectedItem.hasTie + // Accidentals + property int selectedId: idArray[scoreObj.cursorAlter + 2] + property string text: selectedId > -1 ? accidGlyphs[selectedId] : "" + property int alter: accidArray[selectedId + 1] + readonly property var accidGlyphs: ["\ue264", "\ue260", "\ue262", "\ue263"] + readonly property var accidArray: [0, -2, -1, 1, 2] + readonly property var idArray: [0, 1, -1, 2, 3] + readonly property var rtmActions: [scoreObj.wholeNoteAct, scoreObj.halfNoteAct, scoreObj.quarterNoteAct, scoreObj.eighthNoteAct, scoreObj.sixteenthNoteAct] + readonly property var accidTips: [qsTr("<b>double flat</b> - lowers a note by two semitones (whole tone).<br>On the guitar it is two frets down."), qsTr("<b>flat</b> - lowers a note by a half tone (semitone).<br>On the guitar it is one fret down."), qsTr("<b>sharp</b> - raises a note by a half tone (semitone).<br>On the guitar it is one fret up."), qsTr("<b>double sharp</b> - raises a note by two semitones (whole tone).<br>On the guitar it is two frets up.")] + + x: show ? 2 : -width - NOO.factor() + y: score.singleNote || score.meter === Tmeter.NoMeter ? (score.height - height) / 2 : (NOO.isAndroid() ? (nootkaWindow.height - height) / 2 : NOO.factor() / 2) + z: 1010 // above mobile menu button + visible: !scoreObj.touched && loader.active + active: !score.readOnly && (scoreObj.activeNote || (score.noteAdd && score.noteAdd.active)) + factor: NOO.isAndroid() ? NOO.shortScreenSide() * 0.04 : NOO.factor() * 1.2 + + Component { + id: ctrlButtonComp + + ControlButton { + property int rhythm: 1 + property bool rest: false + factor: toolbox.factor * 0.9 - yOffset: factor * -4.4 - visible: score.enableDoubleAccids || index === 1 || index === 2 - selected: selectedId === index - font { family: "scorek"; pixelSize: factor * 3 } - text: accidGlyphs[index] - // HACK: '$' symbol never occurs, so for guitars it is just entire string, when for others just musical part of the text - statusTip: scoreObj.riseAct ? accidTips[index].split(GLOB.instrument.isGuitar ? "$" : "<br>")[0] : "" - onClicked: scoreObj.cursorAlter = accidArray[(selectedId === index ? -1 : index) + 1] + yOffset: factor * 0.5 + text: NOO.rhythmText(NOO.rhythm(rhythm, rest, false, false)) + selected: rhythm === scoreObj.workRtmValue && rest === scoreObj.workRtmRest onEntered: hideTimer.stop() onExited: hideTimer.restart() - } + + font { + family: "nootka" + pixelSize: factor * 2 + } + } - } - - Rectangle { visible: score.meter !== Tmeter.NoMeter; width: toolbox.width; height: 1; color: activPal.text } - - Grid { - visible: score.meter !== Tmeter.NoMeter - columns: 2 - Repeater { - model: 10 - Loader { - sourceComponent: ctrlButtonComp - onLoaded: { - item.rhythm = 1 + index / 2 - item.rest = index % 2 === 0 - if (index % 2 === 1) { - var act = rtmActions[Math.floor(index / 2)] - if (act) - item.statusTip = act.text + "<br><b>(" + act.key() + ")</b>" - } + + } + + Connections { + target: scoreObj + onScoreWasCleared: show = false + onEditModeChanged: show = scoreObj.editMode && scoreObj.activeNote + } + + component: Component { + id: contentComp + + Column { + Grid { + columns: score.meter === Tmeter.NoMeter ? 1 : 2 + anchors.horizontalCenter: parent.horizontalCenter + + Repeater { + model: 4 + + ControlButton { + factor: toolbox.factor * 0.9 + yOffset: factor * -4.4 + visible: score.enableDoubleAccids || index === 1 || index === 2 + selected: selectedId === index + text: accidGlyphs[index] + // HACK: '$' symbol never occurs, so for guitars it is just entire string, when for others just musical part of the text + statusTip: scoreObj.riseAct ? accidTips[index].split(GLOB.instrument.isGuitar ? "$" : "<br>")[0] : "" + onClicked: scoreObj.cursorAlter = accidArray[(selectedId === index ? -1 : index) + 1] + onEntered: hideTimer.stop() + onExited: hideTimer.restart() + + font { + family: "scorek" + pixelSize: factor * 3 + } + + } + + } + } - Connections { - target: item - onClicked: { scoreObj.workRtmValue = item.rhythm; scoreObj.workRtmRest = item.rest } + + Rectangle { + visible: score.meter !== Tmeter.NoMeter + width: toolbox.width + height: 1 + color: activPal.text } - } - } - Loader { // triplet - id: tripLoad - sourceComponent: ctrlButtonComp - onLoaded: { item.rhythm = 0; item.text = " " /*"\u0183"*/ } - Binding { target: tripLoad.item; property: "selected"; value: toolbox.triplet } -// Connections { -// target: tripLoad.item -// onClicked: { toolbox.triplet = !tripLoad.item.selected; scoreObj.workRhythm = rhythm } -// } - } - Loader { // dot - id: dotLoad - sourceComponent: ctrlButtonComp - onLoaded: { - item.rhythm = 0 - item.text = "." - if (scoreObj.dotNoteAct) - item.statusTip = scoreObj.dotNoteAct.text + "<br><b>(" + scoreObj.dotNoteAct.key() + ")</b>" - } - Binding { target: dotLoad.item; property: "selected"; value: scoreObj.workRtmDot } - Binding { target: dotLoad.item; property: "enabled"; value: scoreObj.workRtmValue !== Trhythm.Sixteenth } - Connections { - target: dotLoad.item - onClicked: scoreObj.workRtmDot = !scoreObj.workRtmDot - } - } - } - - ControlButton { // tie - visible: score.meter !== Tmeter.NoMeter - anchors.horizontalCenter: parent.horizontalCenter - factor: toolbox.factor - selected: toolbox.tie - height: factor * 1.5; width: factor * 2.7 - yOffset: (height - textHeight) / 2 - factor - font { family: "nootka"; pixelSize: factor * 6 } - text: "\ue18c" - onClicked: scoreObj.checkTieOfSelected() - statusTip: qsTr("Tie - connect or disconnect selected note with previous one if both notes have the same pitch.") + "<br><b>(L)</b>" - onEntered: hideTimer.stop() - onExited: hideTimer.restart() - } - - Rectangle { visible: scoreObj.enableTechnical; width: toolbox.width; height: 1; color: activPal.text } - - Grid { - visible: scoreObj.enableTechnical - columns: score.meter === Tmeter.NoMeter ? 1 : 2 - anchors.horizontalCenter: parent.horizontalCenter - Repeater { - model: [ "\uE610", "\uE612" ] - ControlButton { - factor: toolbox.factor * 0.9 - yOffset: factor * 0.5 - font { family: "nootka"; pixelSize: factor * 2 } - text: modelData - statusTip: NOO.TR("Bandoneon", index === 0 ? "Bellows is opening." : "Bellows is closing.") - onClicked: { - show = false - if (scoreObj.selectedItem) { - var b = index === 0 ? TnoteItem.BowDown : TnoteItem.BowUp - if (scoreObj.selectedItem.bowing() === b) - b = TnoteItem.BowUndefined - scoreObj.selectedItem.setBowing(b) - } + + Grid { + visible: score.meter !== Tmeter.NoMeter + columns: 2 + + Repeater { + model: 10 + + Loader { + sourceComponent: ctrlButtonComp + onLoaded: { + item.rhythm = 1 + index / 2; + item.rest = index % 2 === 0; + if (index % 2 === 1) { + var act = rtmActions[Math.floor(index / 2)]; + if (act) + item.statusTip = act.text + "<br><b>(" + act.key() + ")</b>"; + + } + } + + Connections { + target: item + onClicked: { + scoreObj.workRtmValue = item.rhythm; + scoreObj.workRtmRest = item.rest; + } + } + + } + + } + // triplet + + Loader { + // target: tripLoad.item + // onClicked: { toolbox.triplet = !tripLoad.item.selected; scoreObj.workRhythm = rhythm } + // } + + id: tripLoad + + sourceComponent: ctrlButtonComp + onLoaded: { + item.rhythm = 0; + item.text = " "; + } //"\u0183" + + Binding { + target: tripLoad.item + property: "selected" + value: toolbox.triplet + } + // Connections { + + } + // dot + + Loader { + id: dotLoad + + sourceComponent: ctrlButtonComp + onLoaded: { + item.rhythm = 0; + item.text = "."; + if (scoreObj.dotNoteAct) + item.statusTip = scoreObj.dotNoteAct.text + "<br><b>(" + scoreObj.dotNoteAct.key() + ")</b>"; + + } + + Binding { + target: dotLoad.item + property: "selected" + value: scoreObj.workRtmDot + } + + Binding { + target: dotLoad.item + property: "enabled" + value: scoreObj.workRtmValue !== Trhythm.Sixteenth + } + + Connections { + target: dotLoad.item + onClicked: scoreObj.workRtmDot = !scoreObj.workRtmDot + } + + } + } - //TODO select bow control according to currently selected note -// onVisibleChanged: selected = scoreObj.selectedItem && scoreObj.selectedItem.bowing() === (index === 0 ? TnoteItem.BowDown : TnoteItem.BowUp) - onEntered: hideTimer.stop() - onExited: hideTimer.restart() - } + + // tie + ControlButton { + visible: score.meter !== Tmeter.NoMeter + anchors.horizontalCenter: parent.horizontalCenter + factor: toolbox.factor + selected: toolbox.tie + height: factor * 1.5 + width: factor * 2.7 + yOffset: (height - textHeight) / 2 - factor + text: "\ue18c" + onClicked: scoreObj.checkTieOfSelected() + statusTip: qsTr("Tie - connect or disconnect selected note with previous one if both notes have the same pitch.") + "<br><b>(L)</b>" + onEntered: hideTimer.stop() + onExited: hideTimer.restart() + + font { + family: "nootka" + pixelSize: factor * 6 + } + + } + + Rectangle { + visible: scoreObj.enableTechnical + width: toolbox.width + height: 1 + color: activPal.text + } + + Grid { + visible: scoreObj.enableTechnical + columns: score.meter === Tmeter.NoMeter ? 1 : 2 + anchors.horizontalCenter: parent.horizontalCenter + + Repeater { + model: ["\uE610", "\uE612"] + + ControlButton { + factor: toolbox.factor * 0.9 + yOffset: factor * 0.5 + text: modelData + statusTip: NOO.TR("Bandoneon", index === 0 ? "Bellows is opening." : "Bellows is closing.") + onClicked: { + show = false; + if (scoreObj.selectedItem) { + var b = index === 0 ? TnoteItem.BowDown : TnoteItem.BowUp; + if (scoreObj.selectedItem.bowing() === b) + b = TnoteItem.BowUndefined; + + scoreObj.selectedItem.setBowing(b); + } + } + //TODO select bow control according to currently selected note + // onVisibleChanged: selected = scoreObj.selectedItem && scoreObj.selectedItem.bowing() === (index === 0 ? TnoteItem.BowDown : TnoteItem.BowUp) + onEntered: hideTimer.stop() + onExited: hideTimer.restart() + + font { + family: "nootka" + pixelSize: factor * 2 + } + + } + + } + + } + } - } + } - } - Connections { - target: scoreObj - onScoreWasCleared: show = false - onEditModeChanged: show = scoreObj.editMode && scoreObj.activeNote - } + Behavior on x { + enabled: GLOB.useAnimations + + SpringAnimation { + spring: 2 + damping: 0.3 + duration: 300 + } - Behavior on x { enabled: GLOB.useAnimations; SpringAnimation { spring: 2; damping: 0.3; duration: 300 }} + } } diff --git a/src/qml/score/Staff.qml b/src/qml/score/Staff.qml index 69a2ffa0bee5da2e600a46975ca6bca4d42cda4f..5aae6a06d4f2c482df69b5dcb1cb0ae871367a16 100644 --- a/src/qml/score/Staff.qml +++ b/src/qml/score/Staff.qml @@ -2,96 +2,116 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 +import Nootka.Music import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Window 2.12 - -import Nootka.Music -import Nootka 1.0 import Score 1.0 - TstaffItem { - id: staff - - property alias clef: clef - - property real linesCount: score.clef === Tclef.PianoStaffClefs ? 49 : 38 - property var keySignItem: null - property var meter: null - property real firstNoteX: (meter ? meter.x + meter.width : (keySignItem ? keySignItem.x + keySignItem.width : clef.x + clef.width)) + 1.0 - - height: linesCount - scale: score.singleNote ? Math.min(score.height / linesCount, score.width / 46) : - (Math.min(Math.min(score.height, score.width / 2), - Math.max(Screen.height / 4, Screen.pixelDensity * (NOO.isAndroid() ? 50 : 70)) - ) / linesCount) * score.scaleFactor - width: score.width / scale - transformOrigin: Item.TopLeft - - scoreObject: scoreObj - notesIndent: firstNoteX - upperLine: score.clef === Tclef.PianoStaffClefs ? 14 : 16 - - TstaffLines { - id: upperStaff - x: score.clef === Tclef.PianoStaffClefs ? 3 : 0.5 - width: staff.width - (score.clef === Tclef.PianoStaffClefs ? 3.5 : 1) - y: upperLine - 0.1 - staffScale: staff.scale - } - - Loader { sourceComponent: score.clef === Tclef.PianoStaffClefs ? lowerStaff : null } - Component { - id: lowerStaff - TstaffLines { + id: staff + + property alias clef: clef + property real linesCount: score.clef === Tclef.PianoStaffClefs ? 49 : 38 + property var keySignItem: null + property var meter: null + property real firstNoteX: (meter ? meter.x + meter.width : (keySignItem ? keySignItem.x + keySignItem.width : clef.x + clef.width)) + 1 + + function checkIsKeyEnabled() { + // key signature created on demand + if (score.enableKeySign) { + if (!keySignItem) + keySignItem = Qt.createComponent("qrc:/score/KeySignature.qml").createObject(staff); + + } else { + if (keySignItem) { + keySignItem.destroy(); + keySignItem = null; + } + } + } + + height: linesCount + scale: score.singleNote ? Math.min(score.height / linesCount, score.width / 46) : (Math.min(Math.min(score.height, score.width / 2), Math.max(Screen.height / 4, Screen.pixelDensity * (NOO.isAndroid() ? 50 : 70))) / linesCount) * score.scaleFactor + width: score.width / scale + transformOrigin: Item.TopLeft + scoreObject: scoreObj + notesIndent: firstNoteX + upperLine: score.clef === Tclef.PianoStaffClefs ? 14 : 16 + Component.onCompleted: checkIsKeyEnabled() + + TstaffLines { + id: upperStaff + x: score.clef === Tclef.PianoStaffClefs ? 3 : 0.5 width: staff.width - (score.clef === Tclef.PianoStaffClefs ? 3.5 : 1) - y: upperLine - 0.1 + 22 + y: upperLine - 0.1 staffScale: staff.scale - } - } - - Loader { sourceComponent: score.clef === Tclef.PianoStaffClefs ? brace : null } - Component { - id: brace - Text { - text: "\ue003" - font {family: "scorek"; pixelSize: 21 } - y: -14; x: 3.1 + } + + Loader { + sourceComponent: score.clef === Tclef.PianoStaffClefs ? lowerStaff : null + } + + Component { + id: lowerStaff + + TstaffLines { + x: score.clef === Tclef.PianoStaffClefs ? 3 : 0.5 + width: staff.width - (score.clef === Tclef.PianoStaffClefs ? 3.5 : 1) + y: upperLine - 0.1 + 22 + staffScale: staff.scale + } + + } + + Loader { + sourceComponent: score.clef === Tclef.PianoStaffClefs ? brace : null + } + + Component { + id: brace + + Text { + text: "\ue003" + y: -14 + x: 3.1 + color: activPal.text + + font { + family: "scorek" + pixelSize: 21 + } + + } + + } + + Clef { + id: clef + } + + Connections { + target: score + onEnableKeySignChanged: checkIsKeyEnabled() + } + + // measure number + Text { + x: score.clef === Tclef.PianoStaffClefs ? 0.8 : 0.5 + y: upperLine - (score.clef === Tclef.Treble_G || score.clef === Tclef.Treble_G_8down || score.clef === Tclef.Tenor_C || score.clef === Tclef.PianoStaffClefs ? 8 : 5) + text: firstMeasureNr + 1 + visible: number > 0 && firstMeasureNr > 0 + scale: 0.4 + transformOrigin: Item.TopLeft color: activPal.text - } - } - - Clef { id: clef } - - Connections { - target: score - onEnableKeySignChanged: checkIsKeyEnabled() - } - - Text { // measure number - x: score.clef === Tclef.PianoStaffClefs ? 0.8 : 0.5 - y: upperLine - (score.clef === Tclef.Treble_G || score.clef === Tclef.Treble_G_8down - || score.clef === Tclef.Tenor_C || score.clef === Tclef.PianoStaffClefs ? 8 : 5) - text: firstMeasureNr + 1 - visible: number > 0 && firstMeasureNr > 0 - scale: 0.4; transformOrigin: Item.TopLeft - font { pixelSize: score.clef === Tclef.PianoStaffClefs ? 7 : 5; family: "Scorek" } - color: activPal.text - } - - function checkIsKeyEnabled() { // key signature created on demand - if (score.enableKeySign) { - if (!keySignItem) - keySignItem = Qt.createComponent("qrc:/score/KeySignature.qml").createObject(staff) - } else { - if (keySignItem) { - keySignItem.destroy() - keySignItem = null + + font { + pixelSize: score.clef === Tclef.PianoStaffClefs ? 7 : 5 + family: "Scorek" } + } - } - Component.onCompleted: checkIsKeyEnabled() } diff --git a/src/qml/score/Tie.qml b/src/qml/score/Tie.qml index d27dd7eb35941e5c205806268612217146fd3410..87e67b06eff71a9cba3a371cfede3d56451b67ba 100644 --- a/src/qml/score/Tie.qml +++ b/src/qml/score/Tie.qml @@ -4,15 +4,23 @@ import QtQuick 2.12 - Text { - id: tie - property alias xScale: sc.xScale - property bool stemDown: false + id: tie + + property alias xScale: sc.xScale + property bool stemDown: false + + text: stemDown ? "\ue204" : "\ue1fd" + y: stemDown ? -1.25 : -0.5 + z: -20 + + font { + family: "Scorek" + pixelSize: 7 + } + + transform: Scale { + id: sc + } - font { family: "Scorek"; pixelSize: 7 } - text: stemDown ? "\ue204" : "\ue1fd" - transform: Scale { id: sc } - y: stemDown ? -1.25 : -0.5 - z: - 20 } diff --git a/src/qml/settings/ColorButton.qml b/src/qml/settings/ColorButton.qml index fb68b01edcc71821587abb1208b88f6dea2a7413..1fd8dc853b05949db27a8507a5137618a9f90c81 100644 --- a/src/qml/settings/ColorButton.qml +++ b/src/qml/settings/ColorButton.qml @@ -2,41 +2,46 @@ * 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.Dialogs 1.2 -import Nootka 1.0 -import "../" - - TcuteButton { - id: colorButton + id: colorButton + + property alias title: colorDialog.title - property alias title: colorDialog.title + implicitWidth: NOO.factor() * 3.5 + implicitHeight: NOO.factor() * 2 + onClicked: colorDialog.open() + contentItem: null + checked: !enabled - Behavior on color { enabled: GLOB.useAnimations; ColorAnimation { duration: 750 }} + // disable cover + Rectangle { + anchors.fill: background + visible: !colorButton.enabled + color: disdPal.text + radius: NOO.factor() / 3 + } - implicitWidth: NOO.factor() * 3.5 - implicitHeight: NOO.factor() * 2 + ColorDialog { + id: colorDialog - onClicked: colorDialog.open() + color: colorButton.color + onAccepted: colorButton.color = colorDialog.color + modality: Qt.WindowModal + showAlphaChannel: color.a < 1 + } - contentItem: null + Behavior on color { + enabled: GLOB.useAnimations - checked: !enabled + ColorAnimation { + duration: 750 + } - Rectangle { // disable cover - anchors.fill: background - visible: !colorButton.enabled - color: disdPal.text - radius: NOO.factor() / 3 - } + } - ColorDialog { - id: colorDialog - color: colorButton.color - onAccepted: colorButton.color = colorDialog.color - modality: Qt.WindowModal - showAlphaChannel: color.a < 1.0 - } } diff --git a/src/qml/settings/ExamPage.qml b/src/qml/settings/ExamPage.qml index 11f599d00d91e2ec33e8db7cae729edf9a76a772..1eba42cd00ac645530f06a1cbe3f19dd6c60da89 100644 --- a/src/qml/settings/ExamPage.qml +++ b/src/qml/settings/ExamPage.qml @@ -2,249 +2,370 @@ * 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 Nootka 1.0 -import "../" +Tflickable { + property int mode: 0 // 0 - settings, 1 - exam, 2 - exercise + function save() { + GLOB.autoNextQuestion = autoNextChB.checked; + GLOB.expertAnswers = expertAnswChB.checked; + if (mode === 0 || mode === 2) { + GLOB.suggestExam = suggestChB.checked; + GLOB.waitForCorrect = waitForCorrChB.checked; + GLOB.showWrongPlayed = showWrongChB.checked; + GLOB.extraNames = extraNamesChB.checked; + GLOB.correctAnswers = correctChB.checked; + } + if (mode === 0 || mode === 1) { + GLOB.closeWithoutConfirm = noConfirmChB.checked; + GLOB.repeatIncorect = repeatChB.checked; + } + GLOB.wrongColor = wrongColor.color; + GLOB.notBadColor = notBadColor.color; + GLOB.correctColor = correctColor.color; + if (mode === 0) + GLOB.student = userNameIn.text; -Tflickable { - contentHeight: examCol.height + NOO.factor() * 2 - contentWidth: width + } - property int mode: 0 // 0 - settings, 1 - exam, 2 - exercise + function defaults() { + autoNextChB.checked = false; + expertAnswChB.checked = false; + correctChB.checked = true; + suggestChB.checked = true; + waitForCorrChB.checked = true; + showWrongChB.checked = false; + extraNamesChB.checked = true; + repeatChB.checked = true; + noConfirmChB.checked = false; + wrongColor.color = Qt.rgba(1, 0, 0, 1); + notBadColor.color = Qt.rgba(1, 0.5, 0, 1); + correctColor.color = Qt.rgba(0, 1, 0, 1); + userNameIn.text = GLOB.student; + } + + function help() { + NOO.openDocLink("2017/05/17/exercises-exams-settings/"); + } + + contentHeight: examCol.height + NOO.factor() * 2 + contentWidth: width + Component.onCompleted: { + autoNextChB.checked = GLOB.autoNextQuestion; + expertAnswChB.checked = GLOB.expertAnswers; + correctChB.checked = GLOB.correctAnswers; + suggestChB.checked = GLOB.suggestExam; + waitForCorrChB.checked = GLOB.waitForCorrect; + showWrongChB.checked = GLOB.showWrongPlayed; + extraNamesChB.checked = GLOB.extraNames; + repeatChB.checked = GLOB.repeatIncorect; + noConfirmChB.checked = GLOB.closeWithoutConfirm; + } - Column { - id: examCol - width: parent.width; topPadding: NOO.factor() - spacing: NOO.factor() + Column { + id: examCol - Tframe { - width: parent.width * 0.98 - anchors.horizontalCenter: parent.horizontalCenter - Column { width: parent.width - spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 - Tile { - visible: mode === 0 - description: qsTr("Default name for every new exam or exercise.") - Row { - spacing: NOO.factor() + topPadding: NOO.factor() + spacing: NOO.factor() + + Tframe { + width: parent.width * 0.98 anchors.horizontalCenter: parent.horizontalCenter - Text { text: NOO.TR("StartExam", "student name:"); color: activPal.text; anchors.verticalCenter: parent.verticalCenter } - TtextField { - id: userNameIn - anchors.verticalCenter: parent.verticalCenter - placeholderText: NOO.TR("StartExam", "Enter your name or nick-name.") - font.pixelSize: NOO.factor(); maximumLength: 40 - width: NOO.factor() * 25 - horizontalAlignment: TextInput.AlignHCenter - text: GLOB.student - } - } - } - Grid { - columns: expertAnswChB.width + autoNextChB.width + NOO.factor() * 4 > parent.width * 0.96 ? 1 : 2 - anchors.horizontalCenter: parent.horizontalCenter - horizontalItemAlignment: Grid.AlignHCenter - Tile { - width: autoNextChB.width + NOO.factor() * 2 - anchors.horizontalCenter: undefined - TcheckBox { - id: autoNextChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTranslate("TexamHelp", "ask next question automatically") - } - } - Tile { - width: expertAnswChB.width + NOO.factor() * 2 - anchors.horizontalCenter: undefined - TcheckBox { - id: expertAnswChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTranslate("TexamHelp", "check answers without requiring confirmation") - onClicked: { - if (expertAnswChB.checked) { - expertDialog.open() + + Column { + width: parent.width + spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 + + Tile { + visible: mode === 0 + description: qsTr("Default name for every new exam or exercise.") + + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + Text { + text: NOO.TR("StartExam", "student name:") + color: activPal.text + anchors.verticalCenter: parent.verticalCenter + } + + TtextField { + id: userNameIn + + anchors.verticalCenter: parent.verticalCenter + placeholderText: NOO.TR("StartExam", "Enter your name or nick-name.") + font.pixelSize: NOO.factor() + maximumLength: 40 + width: NOO.factor() * 25 + horizontalAlignment: TextInput.AlignHCenter + text: GLOB.student + } + + } + } - } + + Grid { + columns: expertAnswChB.width + autoNextChB.width + NOO.factor() * 4 > parent.width * 0.96 ? 1 : 2 + anchors.horizontalCenter: parent.horizontalCenter + horizontalItemAlignment: Grid.AlignHCenter + + Tile { + width: autoNextChB.width + NOO.factor() * 2 + anchors.horizontalCenter: undefined + + TcheckBox { + id: autoNextChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTranslate("TexamHelp", "ask next question automatically") + } + + } + + Tile { + width: expertAnswChB.width + NOO.factor() * 2 + anchors.horizontalCenter: undefined + + TcheckBox { + id: expertAnswChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTranslate("TexamHelp", "check answers without requiring confirmation") + onClicked: { + if (expertAnswChB.checked) + expertDialog.open(); + + } + } + + } + + } + + Tile { + visible: mode === 0 || mode === 2 + description: qsTr("When you will make mistake, the program will show you automatically how a correct answer should be.") + + TcheckBox { + id: correctChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTranslate("TexamHelp", "correct mistakes (exercises only)") + } + + } + + Grid { + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() * 2 + columns: wrongColor.parent.width + correctColor.parent.width + notBadColor.parent.width + NOO.factor() * 4 < parent.width ? 3 : (wrongColor.parent.width + correctColor.parent.width + spacing < parent.width ? 2 : 1) + horizontalItemAlignment: Grid.AlignHCenter + + Row { + spacing: NOO.factor() / 2 + + TlabelText { + text: qsTr("color of questions") + } + + ColorButton { + id: wrongColor + + color: GLOB.wrongColor + title: qsTr("color of questions") + } + + } + + Row { + spacing: NOO.factor() / 2 + + TlabelText { + text: qsTr("color of answers") + } + + ColorButton { + id: correctColor + + color: GLOB.correctColor + title: qsTr("color of answers") + } + + } + + Row { + spacing: NOO.factor() / 2 + + TlabelText { + text: qsTr("color of 'not bad' answers") + } + + ColorButton { + id: notBadColor + + color: GLOB.notBadColor + title: qsTr("color of 'not bad' answers") + } + + } + + } + } - } - } - Tile { - visible: mode === 0 || mode === 2 - TcheckBox { - id: correctChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTranslate("TexamHelp", "correct mistakes (exercises only)") - } - description: qsTr("When you will make mistake, the program will show you automatically how a correct answer should be.") - } - Grid { - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() * 2 - columns: wrongColor.parent.width + correctColor.parent.width + notBadColor.parent.width + NOO.factor() * 4 < parent.width ? 3 - : (wrongColor.parent.width + correctColor.parent.width + spacing < parent.width ? 2 : 1) - horizontalItemAlignment: Grid.AlignHCenter - - Row { - spacing: NOO.factor() / 2 - TlabelText { text: qsTr("color of questions") } - ColorButton { id: wrongColor; color: GLOB.wrongColor; title: qsTr("color of questions") } - } - Row { - spacing: NOO.factor() / 2 - TlabelText { text: qsTr("color of answers") } - ColorButton { id: correctColor; color: GLOB.correctColor; title: qsTr("color of answers") } - } - Row { - spacing: NOO.factor() / 2 - TlabelText { text: qsTr("color of 'not bad' answers") } - ColorButton { id: notBadColor; color: GLOB.notBadColor; title: qsTr("color of 'not bad' answers") } - } - } - } - } - Tframe { // Exercises frame - visible: mode === 0 || mode === 2 - width: parent.width * 0.98 - anchors.horizontalCenter: parent.horizontalCenter - Column { - width: parent.width - spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 - Text { text: NOO.TR("TexamHelp", "Exercises"); color: activPal.text; font.bold: true } - Tile { - TcheckBox { - id: suggestChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("suggest an exam") - } - description: qsTr("Watch exercising progress and when it is going well, suggest to start an exam on the exercise level.") } - Tile { - TcheckBox { - id: waitForCorrChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("wait for correct note") - } - description: qsTr("When melody is played from score, every note is checked immediately and next note can be played only when the previous one was correct. When unset, notes are checked only after playing the last one (or check button was clicked).") - } - Tile { - TcheckBox { - id: showWrongChB + + // Exercises frame + Tframe { + visible: mode === 0 || mode === 2 + width: parent.width * 0.98 anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("show wrong played") - } - description: qsTr("When answer was played (or sung) and it was wrong also the detected wrong note is shown.") + + Column { + width: parent.width + spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 + + Text { + text: NOO.TR("TexamHelp", "Exercises") + color: activPal.text + font.bold: true + } + + Tile { + description: qsTr("Watch exercising progress and when it is going well, suggest to start an exam on the exercise level.") + + TcheckBox { + id: suggestChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("suggest an exam") + } + + } + + Tile { + description: qsTr("When melody is played from score, every note is checked immediately and next note can be played only when the previous one was correct. When unset, notes are checked only after playing the last one (or check button was clicked).") + + TcheckBox { + id: waitForCorrChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("wait for correct note") + } + + } + + Tile { + description: qsTr("When answer was played (or sung) and it was wrong also the detected wrong note is shown.") + + TcheckBox { + id: showWrongChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("show wrong played") + } + + } + + Tile { + description: qsTr("To improve association of note in the score or position on the instrument to note name, Nootka will display names even if neither question nor answer is related to it.") + + TcheckBox { + id: extraNamesChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("extra names") + } + + } + + } + } - Tile { - TcheckBox { - id: extraNamesChB + + // Exam frame + Tframe { + visible: mode === 0 || mode === 1 + width: parent.width * 0.98 anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("extra names") - } - description: qsTr("To improve association of note in the score or position on the instrument to note name, Nootka will display names even if neither question nor answer is related to it.") + + Column { + width: parent.width + spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 + + Text { + text: NOO.TR("TexamHelp", "Exams") + color: activPal.text + font.bold: true + } + + Tile { + description: qsTr("A question with an incorrect answer will be asked once again.") + + TcheckBox { + id: repeatChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("repeat a question") + } + + } + + Tile { + description: qsTr("If checked, an application will not ask to answer pending question just mark it as wrong, save an exam to file (in directory: %1) and close itself without any confirmation needed.").arg("<b>" + GLOB.examsDir + "</b>") + + TcheckBox { + id: noConfirmChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("close without confirm") + } + + } + + } + } - } + } - Tframe { // Exam frame - visible: mode === 0 || mode === 1 - width: parent.width * 0.98 - anchors.horizontalCenter: parent.horizontalCenter - Column { - width: parent.width - spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 - Text { text: NOO.TR("TexamHelp", "Exams"); color: activPal.text; font.bold: true } - Tile { - TcheckBox { - id: repeatChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("repeat a question") - } - description: qsTr("A question with an incorrect answer will be asked once again.") + TpopupDialog { + id: expertDialog + + bgColor: Qt.tint(activPal.window, NOO.alpha("red", 20)) + modal: true + caption: qsTr("Experts mode") + onRejected: expertAnswChB.checked = false + + border { + color: "red" + width: NOO.factor() / 4 } - Tile { - TcheckBox { - id: noConfirmChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("close without confirm") - } - description: qsTr("If checked, an application will not ask to answer pending question just mark it as wrong, save an exam to file (in directory: %1) and close itself without any confirmation needed.").arg("<b>" + GLOB.examsDir + "</b>") + + Tflickable { + height: parent.height + contentHeight: expText.height + NOO.factor() * 2 + + Text { + id: expText + + width: parent.width + color: activPal.text + wrapMode: Text.WordWrap + textFormat: Text.StyledText + horizontalAlignment: Text.AlignHCenter + text: "<h4>" + qsTr("You are about to enter expert mode.<br> In this mode you don't need to confirm every answer,<br><b>but remember the following:") + "</b></h4><ul><li>" + qsTr("Selecting a note on the score or a position on the fingerboard invokes automatic checking of your answer, so select a key signature first, if required.") + "<br></li><li>" + qsTr("When an answer is the name of a note <b>first select a proper accidental and an octave</b> and then click a note button - this automatically invokes checking.") + "<br></li><li>" + qsTr("When you have to play a note as an answer - the first detected sound will be taken, so be sure that your input device captures exactly what you want.") + "<br></li><li>" + qsTr("When the last note of question that is a melody was played - checking starts.") + "<br></li></ul>" + } + } - } - } - } - - TpopupDialog { - id: expertDialog - bgColor: Qt.tint(activPal.window, NOO.alpha("red", 20)) - border { color: "red"; width: NOO.factor() / 4.0 } - modal: true - caption: qsTr("Experts mode") - Tflickable { - height: parent.height; contentHeight: expText.height + NOO.factor() * 2 - Text { - id: expText - width: parent.width; color: activPal.text - wrapMode: Text.WordWrap; textFormat: Text.StyledText; horizontalAlignment: Text.AlignHCenter - text: "<h4>" + qsTr("You are about to enter expert mode.<br> In this mode you don't need to confirm every answer,<br><b>but remember the following:") + "</b></h4><ul><li>" + qsTr("Selecting a note on the score or a position on the fingerboard invokes automatic checking of your answer, so select a key signature first, if required.") + "<br></li><li>" + qsTr("When an answer is the name of a note <b>first select a proper accidental and an octave</b> and then click a note button - this automatically invokes checking.") + "<br></li><li>" + qsTr("When you have to play a note as an answer - the first detected sound will be taken, so be sure that your input device captures exactly what you want.") + "<br></li><li>" + qsTr("When the last note of question that is a melody was played - checking starts.") + "<br></li></ul>" - } - } - onRejected: expertAnswChB.checked = false - } - - Component.onCompleted: { - autoNextChB.checked = GLOB.autoNextQuestion - expertAnswChB.checked = GLOB.expertAnswers - correctChB.checked = GLOB.correctAnswers - suggestChB.checked = GLOB.suggestExam - waitForCorrChB.checked = GLOB.waitForCorrect - showWrongChB.checked = GLOB.showWrongPlayed - extraNamesChB.checked = GLOB.extraNames - repeatChB.checked = GLOB.repeatIncorect - noConfirmChB.checked = GLOB.closeWithoutConfirm - } - - function save() { - GLOB.autoNextQuestion = autoNextChB.checked - GLOB.expertAnswers = expertAnswChB.checked - if (mode === 0 || mode === 2) { - GLOB.suggestExam = suggestChB.checked - GLOB.waitForCorrect = waitForCorrChB.checked - GLOB.showWrongPlayed = showWrongChB.checked - GLOB.extraNames = extraNamesChB.checked - GLOB.correctAnswers = correctChB.checked } - if (mode === 0 || mode === 1) { - GLOB.closeWithoutConfirm = noConfirmChB.checked - GLOB.repeatIncorect = repeatChB.checked - } - GLOB.wrongColor = wrongColor.color - GLOB.notBadColor = notBadColor.color - GLOB.correctColor = correctColor.color - if (mode === 0) - GLOB.student = userNameIn.text - } - - function defaults() { - autoNextChB.checked = false - expertAnswChB.checked = false - correctChB.checked = true - suggestChB.checked = true - waitForCorrChB.checked = true - showWrongChB.checked = false - extraNamesChB.checked = true - repeatChB.checked = true - noConfirmChB.checked = false - wrongColor.color = Qt.rgba(1, 0, 0, 1) - notBadColor.color = Qt.rgba(1, 0.5, 0, 1) - correctColor.color = Qt.rgba(0, 1, 0, 1) - userNameIn.text = GLOB.student - } - - function help() { NOO.openDocLink("2017/05/17/exercises-exams-settings/") } + } diff --git a/src/qml/settings/GlobalPage.qml b/src/qml/settings/GlobalPage.qml index ff585d094141e9ac2fc564a17a6c5701a895ef73..07a35c9073f779c4d5a2713646d1fe18ca79ba95 100644 --- a/src/qml/settings/GlobalPage.qml +++ b/src/qml/settings/GlobalPage.qml @@ -2,243 +2,371 @@ * Copyright (C) 2017-2025 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.Dialogs 1.2 -import Nootka 1.0 -import "../" +Tflickable { + id: globalPage + property var updater: null -Tflickable { - id: globalPage - height: parent.height - - contentHeight: mainColumn.height + NOO.factor() * 2 - - Column { - id: mainColumn - spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 - width: parent.width - - Tile { - description: qsTr("Select a language.<br><span style=\"color: red;\">To take effect, this requires restarting the application!</span>") - - ListModel { - id: langModel - ListElement { flag: "default"; lang: QT_TR_NOOP("default") } - ListElement { flag:"cs"; lang: "Český" } - ListElement { flag:"de"; lang: "Deutsch" } - ListElement { flag:"en"; lang: "English" } - ListElement { flag:"es"; lang: "Español" } - ListElement { flag:"fr"; lang: "Français" } - ListElement { flag:"hu"; lang: "Magyar" } - ListElement { flag:"it"; lang: "Italiano" } - ListElement { flag:"pl"; lang: "polski" } - ListElement { flag:"br"; lang: "português brasileiro" } - ListElement { flag:"ru"; lang: "Русский" } - ListElement { flag:"sl"; lang: "Slovenščina" } - ListElement { flag:"ta"; lang: "தமிழ்" } - ListElement { flag:"uk"; lang: "Українська" } - } - - Tumbler { - id: langTumb + function save() { + GLOB.useAnimations = animChBox.checked; + GLOB.showHints = hintsChBox.checked; + GLOB.lang = langTumb.currentIndex === 0 ? "" : langModel.get(langTumb.currentIndex).flag; + GLOB.scale = scaleSlider.value; + } + + function defaults() { + animChBox.checked = true; + hintsChBox.checked = true; + langTumb.currentIndex = 0; + scaleSlider.value = 1; + } + + function help() { + NOO.openDocLink("2017/05/17/settings/"); + } + + height: parent.height + contentHeight: mainColumn.height + NOO.factor() * 2 + + Column { + id: mainColumn + + spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 width: parent.width - height: NOO.factor() * (NOO.isAndroid() ? 6 : 8) - visibleItemCount: Math.min(((width / (NOO.factor() * (NOO.isAndroid() ? 5.5 : 7))) / 2) * 2 - 1, 7) - model: langModel - delegate: Component { - Column { - spacing: NOO.factor() / 4 - opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) - scale: 1.7 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) - Image { - source: NOO.pix("flags/" + flag) - height: langTumb.height * 0.375; width: height * (sourceSize.height / sourceSize.width) - anchors.horizontalCenter: parent.horizontalCenter - MouseArea { - anchors.fill: parent - onClicked: langTumb.currentIndex = index - } + + Tile { + description: qsTr("Select a language.<br><span style=\"color: red;\">To take effect, this requires restarting the application!</span>") + + ListModel { + id: langModel + + ListElement { + flag: "default" + lang: QT_TR_NOOP("default") + } + + ListElement { + flag: "cs" + lang: "Český" + } + + ListElement { + flag: "de" + lang: "Deutsch" + } + + ListElement { + flag: "en" + lang: "English" + } + + ListElement { + flag: "es" + lang: "Español" + } + + ListElement { + flag: "fr" + lang: "Français" + } + + ListElement { + flag: "hu" + lang: "Magyar" + } + + ListElement { + flag: "it" + lang: "Italiano" + } + + ListElement { + flag: "pl" + lang: "polski" + } + + ListElement { + flag: "br" + lang: "português brasileiro" + } + + ListElement { + flag: "ru" + lang: "Русский" + } + + ListElement { + flag: "sl" + lang: "Slovenščina" + } + + ListElement { + flag: "ta" + lang: "தமிழ்" + } + + ListElement { + flag: "uk" + lang: "Українська" + } + } - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: flag === "default" ? qsTr(lang) : lang - color: activPal.text - height: langTumb.height * 0.15; width: langTumb.height * 1.1 - horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter - font { bold: langTumb.currentIndex === index; pixelSize: langTumb.height * 0.1 } - minimumPixelSize: langTumb.height * 0.05 - lineHeight: 0.8 - fontSizeMode: Text.Fit + + Tumbler { + id: langTumb + + width: parent.width + height: NOO.factor() * (NOO.isAndroid() ? 6 : 8) + visibleItemCount: Math.min(((width / (NOO.factor() * (NOO.isAndroid() ? 5.5 : 7))) / 2) * 2 - 1, 7) + model: langModel + + Rectangle { + z: -1 + width: langTumb.height * 1.1 + height: langTumb.height * 0.7 + x: langTumb.width / 2 - width / 2 + y: langTumb.height * 0.01 + color: NOO.alpha(activPal.highlight, 100) + radius: width / 12 + } + + delegate: Component { + Column { + spacing: NOO.factor() / 4 + opacity: 1 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) + scale: 1.7 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) + + Image { + source: NOO.pix("flags/" + flag) + height: langTumb.height * 0.375 + width: height * (sourceSize.height / sourceSize.width) + anchors.horizontalCenter: parent.horizontalCenter + + MouseArea { + anchors.fill: parent + onClicked: langTumb.currentIndex = index + } + + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: flag === "default" ? qsTr(lang) : lang + color: activPal.text + height: langTumb.height * 0.15 + width: langTumb.height * 1.1 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + minimumPixelSize: langTumb.height * 0.05 + lineHeight: 0.8 + fontSizeMode: Text.Fit + + font { + bold: langTumb.currentIndex === index + pixelSize: langTumb.height * 0.1 + } + + } + + } + + } + + contentItem: PathView { + id: pathView + + model: langTumb.model + delegate: langTumb.delegate + clip: true + pathItemCount: langTumb.visibleItemCount + 1 + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + dragMargin: width / 2 + + path: Path { + startX: 0 + startY: NOO.factor() * 1.4 + + PathLine { + x: pathView.width + y: NOO.factor() * 1.4 + } + + } + + } + } - } + } - contentItem: PathView { - id: pathView - model: langTumb.model - delegate: langTumb.delegate - clip: true - pathItemCount: langTumb.visibleItemCount + 1 - preferredHighlightBegin: 0.5 - preferredHighlightEnd: 0.5 - dragMargin: width / 2 - path: Path { - startX: 0 - startY: NOO.factor() * 1.4 - PathLine { - x: pathView.width - y: NOO.factor() * 1.4 + + Tile { + TcheckBox { + id: animChBox + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("enable animations") + checked: GLOB.useAnimations } - } + } - Rectangle { - z: -1; width: langTumb.height * 1.1; height: langTumb.height * 0.7 - x: langTumb.width / 2 - width / 2; y: langTumb.height * 0.01 - color: NOO.alpha(activPal.highlight, 100) - radius: width / 12 + + Tile { + TcheckBox { + id: hintsChBox + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("show hints") + checked: GLOB.showHints + } + } - } - } - Tile { - TcheckBox { - id: animChBox - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("enable animations") - checked: GLOB.useAnimations - } - } + Tile { + Column { + spacing: NOO.factor() + width: parent.width * 0.9 + anchors.horizontalCenter: parent.horizontalCenter - Tile { - TcheckBox { - id: hintsChBox - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("show hints") - checked: GLOB.showHints - } - } + TcuteButton { + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Check for updates") + onClicked: dialogObj.checkForUpdates() + } + + Text { + color: activPal.text + height: NOO.factor() * 3 + width: parent.width + verticalAlignment: Text.AlignVCenter + text: dialogObj.updateMessage + wrapMode: Text.WordWrap + } + + } - Tile { - Column { - spacing: NOO.factor() - width: parent.width * 0.9 - anchors.horizontalCenter: parent.horizontalCenter - TcuteButton { - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("Check for updates") - onClicked: dialogObj.checkForUpdates() } - Text { - color: activPal.text - height: NOO.factor() * 3; width: parent.width; verticalAlignment: Text.AlignVCenter - text: dialogObj.updateMessage; wrapMode: Text.WordWrap + + Tile { + description: qsTr("Scaling factor of visible texts and others GUI elements.<br>Requires application restart.") + + Row { + spacing: NOO.factor() * 2 + anchors.horizontalCenter: parent.horizontalCenter + + Text { + color: activPal.text + width: NOO.factor() * text.length + text: qsTr("scale") + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: (NOO.factor() / GLOB.scale) * scaleSlider.value + } + + Tslider { + id: scaleSlider + + from: 0.5 + to: 1.5 + stepSize: 0.1 + snapMode: Slider.SnapAlways + value: GLOB.scale + width: Math.min(NOO.factor() * 15, globalPage.width * 0.4) + } + + Text { + anchors.verticalCenter: parent.verticalCenter + text: Math.round(scaleSlider.value * 100) + "%" + font.pixelSize: (NOO.factor() / GLOB.scale) * scaleSlider.value + color: activPal.text + width: NOO.factor() * 3 + horizontalAlignment: Text.AlignHCenter + } + + } + + } + + Item { + height: NOO.factor() * 3 + width: parent.width + } + + Tile { + description: qsTr("All settings will be reset to their default values!<br>Nootka will start up with the first-run wizard.") + descriptionColor: "red" + + TcuteButton { + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Restore all default settings") + onClicked: restoreDialog.open() + } + } - } + } - Tile { - description: qsTr("Scaling factor of visible texts and others GUI elements.<br>Requires application restart.") - Row { - spacing: NOO.factor() * 2 - anchors.horizontalCenter: parent.horizontalCenter - Text { - color: activPal.text; width: NOO.factor() * text.length - text: qsTr("scale") - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: (NOO.factor() / GLOB.scale) * scaleSlider.value + TpopupDialog { + id: restoreDialog + + modal: true + width: Math.min(NOO.factor() * 50, globalPage.width * 0.9) + height: rmmConfTxt.height + NOO.factor() * 8 + bgColor: Qt.tint(activPal.window, NOO.alpha("red", 20)) + caption: qsTr("Restore all default settings") + onAccepted: { + NOO.setResetConfig(true); + Qt.quit(); } - Tslider { - id: scaleSlider - from: 0.5; to: 1.5; stepSize: 0.1; snapMode: Slider.SnapAlways - value: GLOB.scale - width: Math.min(NOO.factor() * 15, globalPage.width * 0.4) + + border { + color: "red" + width: NOO.factor() / 4 } + Text { - anchors.verticalCenter: parent.verticalCenter - text: Math.round(scaleSlider.value * 100) + "%" - font.pixelSize: (NOO.factor() / GLOB.scale) * scaleSlider.value - color: activPal.text; width: NOO.factor() * 3; horizontalAlignment: Text.AlignHCenter + id: rmmConfTxt + + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - NOO.factor() * 2 + color: activPal.text + font.pixelSize: NOO.factor() * 1.2 + text: qsTr("All settings will be reset to their default values!<br>Nootka will start up with the first-run wizard.") + wrapMode: Text.WordWrap } - } + } - Item { height: NOO.factor() * 3; width: parent.width } + // workaround to select 0 item, call it with delay + Timer { + id: langTimer - Tile { - description: qsTr("All settings will be reset to their default values!<br>Nootka will start up with the first-run wizard.") - descriptionColor: "red" - TcuteButton { - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("Restore all default settings") - onClicked: restoreDialog.open() - } + running: true + interval: 50 + onTriggered: { + for (var i = 0; i < langModel.count; ++i) { + if (langModel.get(i).flag === GLOB.lang || (i == 0 && GLOB.lang === "")) { + langTumb.currentIndex = i + 1; // FIXME: workaround for Qt 5.10.1 + langTumb.currentIndex = i; + break; + } + } + } } - } - - TpopupDialog { - id: restoreDialog - modal: true - width: Math.min(NOO.factor() * 50, globalPage.width * 0.9) - height: rmmConfTxt.height + NOO.factor() * 8 - bgColor: Qt.tint(activPal.window, NOO.alpha("red", 20)) - border { color: "red"; width: NOO.factor() / 4.0 } - caption: qsTr("Restore all default settings") - Text { - id: rmmConfTxt - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - NOO.factor() * 2 - color: activPal.text - font.pixelSize: NOO.factor() * 1.2 - text: qsTr("All settings will be reset to their default values!<br>Nootka will start up with the first-run wizard.") - wrapMode: Text.WordWrap - } - onAccepted: { - NOO.setResetConfig(true) - Qt.quit() - } - } - - Timer { // workaround to select 0 item, call it with delay - id: langTimer - running: true - interval: 50 - onTriggered: { - for (var i = 0; i < langModel.count; ++i) { - if (langModel.get(i).flag === GLOB.lang || (i == 0 && GLOB.lang === "")) { - langTumb.currentIndex = i + 1 // FIXME: workaround for Qt 5.10.1 - langTumb.currentIndex = i - break + Connections { + target: dialogObj + onUpdateSummary: { + if (!updater) + updater = Qt.createComponent("qrc:/updater/UpdaterPopup.qml").createObject(globalPage); + + updater.open(); } - } } - } - - function save() { - GLOB.useAnimations = animChBox.checked - GLOB.showHints = hintsChBox.checked - GLOB.lang = langTumb.currentIndex === 0 ? "" : langModel.get(langTumb.currentIndex).flag - GLOB.scale = scaleSlider.value - } - - function defaults() { - animChBox.checked = true - hintsChBox.checked = true - langTumb.currentIndex = 0 - scaleSlider.value = 1.0 - } - - function help() { NOO.openDocLink("2017/05/17/settings/") } - - property var updater: null - Connections { - target: dialogObj - onUpdateSummary: { - if (!updater) - updater = Qt.createComponent("qrc:/updater/UpdaterPopup.qml").createObject(globalPage) - updater.open() - } - } + } diff --git a/src/qml/settings/InstrumentPage.qml b/src/qml/settings/InstrumentPage.qml index bca5b593cd9d96d58c21be3e0f0344be08c52488..604a1f10bc2dd6690363328822368b7a64b22bde 100644 --- a/src/qml/settings/InstrumentPage.qml +++ b/src/qml/settings/InstrumentPage.qml @@ -2,300 +2,432 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import "../" +import "../score" +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 - import Score 1.0 -import Nootka 1.0 -import "../" -import "../score" - Flickable { - id: instrPage + id: instrPage - clip: true - width: parent.width - height: parent.height - contentHeight: instrCol.height + NOO.factor() * 2 - contentWidth: Math.max(width, NOO.factor() * 35) + // private + property bool first: true + // read props first time from GLOB but when instrument changes then from its profile + property int initInstr: -1 + property var currInstr: NOO.instr(instrSel.instrument) - // private - property bool first: true // read props first time from GLOB but when instrument changes then from its profile - property int initInstr: -1 - property var currInstr: NOO.instr(instrSel.instrument) + function setTuning(t) { + for (var i = 0; i < 6; ++i) { + if (i < t.stringNumber) { + if (i >= score.notesCount) + score.addNote(t.str(i + 1)); + else + score.setNote(i, t.str(i + 1)); + score.scoreObj.note(i).setStringNumber(currInstr.isGuitar ? i + 1 : 0); + } else { + if (score.notesCount > t.stringNr()) + score.deleteLast(); - ScrollBar.vertical: ScrollBar { active: false; visible: active } + } + } + stringNrSpin.value = t.stringNumber; + } - Column { - id: instrCol - width: parent.width - spacing: NOO.factor() / 2 - - Tile { - description: qsTr("Instrument") - InstrumentSelector { - id: instrSel - anchors.horizontalCenter: parent.horizontalCenter - onInstrumentChanged: { // load instrument profile - if (first) { - transp.shift = GLOB.transposition - prefFlatRadio.checked = GLOB.preferFlats - } else { - settings.instrument = instrument - currInstr = NOO.instr(instrSel.instrument) // HACK: this slot is called before signal is emitted outside - settings,clef = currInstr.clef - transp.shift = currInstr.transposition - prefFlatRadio.checked = currInstr.isSax ? true : false - prefSharpRadio.checked = currInstr.isSax ? false : true - if (currInstr.isGuitar) { - if (currInstr.bassGuitar) - setTuning(NOO.tuning(Ttune.Bass4_EADG)) - else if (currInstr.ukulele) - setTuning(NOO.tuning(Ttune.Ukulele_GCEA)) - else - setTuning(NOO.tuning(Ttune.Standard_EADGBE)) - fretsNrSpin.value = currInstr.fretNumber - tuningCombo.currentIndex = 0 - fretDots.text = currInstr.ukulele ? "5,7,10,12!" : "5,7,9,12!,15,17" - } else if (currInstr.none) { - setTuning(NOO.tuning(score.scoreObj.lowestNote(), score.scoreObj.highestNote(), NOO.emptyNote(), NOO.emptyNote(), NOO.emptyNote(), NOO.emptyNote())) - } - } - score.ensureVisible(0, 0) + function save() { + GLOB.fingerColor = fingerColorButt.color; + GLOB.selectedColor = selectedColorButt.color; + GLOB.preferFlats = prefFlatRadio.checked; + GLOB.transposition = transp.outShift; + var instrChanged = instrSel.instrument !== initInstr; + if (NOO.instr(instrSel.instrument).isGuitar) { + GLOB.showOtherPos = showOtherPosChB.checked; + GLOB.markedFrets = fretDots.text; + var tun; + if (tuningCombo.currentIndex === tuningCombo.count - 1) { + tun = NOO.tuning(score.scoreObj.noteAt(0), score.scoreObj.noteAt(1), score.scoreObj.noteAt(2), score.scoreObj.noteAt(3), score.scoreObj.noteAt(4), score.scoreObj.noteAt(5)); + } else { + var tunOff = currInstr.bassGuitar ? 100 : (currInstr.ukulele ? 110 : 0); + tun = NOO.tuning(tunOff + tuningCombo.currentIndex); + } + // TODO left-handed guitar + // HACK: when instrument changed, set default tuning at first, then real tuning will show scordature, if any + GLOB.setGuitarParams(fretsNrSpin.value, instrChanged ? NOO.tuning(Ttune.Standard_EADGBE) : tun); + GLOB.setInstrument(instrSel.instrument); + if (instrChanged) + GLOB.setGuitarParams(fretsNrSpin.value, tun); + + } else { + GLOB.setInstrument(instrSel.instrument); + GLOB.setGuitarParams(0, NOO.defaultScale(instrSel.instrument)); } - } + GLOB.audioInstrument = instrSel.instrument; + SOUND.acceptSettings(); } - Tile { - visible: instrSel.instrument <= Tinstrument.BassGuitar || instrSel.instrument == Tinstrument.Ukulele - Column { - spacing: NOO.factor() + function defaults() { + fingerColorButt.color = Qt.rgba(1, 0, 0.5, 0.78); + selectedColorButt.color = Qt.rgba(0.2, 0.6, 1, 1); + GLOB.showOtherPos = false; + instrSel.instrument = initInstr === 0 ? 7 : 0; + instrSel.instrument = initInstr; // switch instrument twice to load its defaults + fretDots.text = currInstr.ukulele ? "5,7,10,12!" : "5,7,9,12!,15,17"; + } + + function help() { + NOO.openDocLink("instrument-settings/"); + } + + clip: true + width: parent.width + height: parent.height + contentHeight: instrCol.height + NOO.factor() * 2 + contentWidth: Math.max(width, NOO.factor() * 35) + + Column { + id: instrCol + width: parent.width - Grid { - visible: NOO.instr(instrSel.instrument).isGuitar - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() - columns: parent.width < NOO.factor() * 50 ? 1 : 2 - horizontalItemAlignment: Grid.AlignHCenter - Row { - spacing: NOO.factor() - Text { text: qsTr("number of frets:"); anchors.verticalCenter: parent.verticalCenter; color: activPal.text } - TspinBox { id: fretsNrSpin; from: 15; to: 24; value: GLOB.fretNumber } - } - Row { - visible: !NOO.instr(instrSel.instrument).ukulele - spacing: NOO.factor() - Text { text: qsTr("number of strings:"); anchors.verticalCenter: parent.verticalCenter; color: activPal.text } - TspinBox { id: stringNrSpin; from: 3; to: 6; value: GLOB.stringNumber() } - } + spacing: NOO.factor() / 2 + + Tile { + description: qsTr("Instrument") + + InstrumentSelector { + id: instrSel + + anchors.horizontalCenter: parent.horizontalCenter + onInstrumentChanged: { + // load instrument profile + if (first) { + transp.shift = GLOB.transposition; + prefFlatRadio.checked = GLOB.preferFlats; + } else { + settings.instrument = instrument; + currInstr = NOO.instr(instrSel.instrument); // HACK: this slot is called before signal is emitted outside + settings, clef = currInstr.clef; + transp.shift = currInstr.transposition; + prefFlatRadio.checked = currInstr.isSax ? true : false; + prefSharpRadio.checked = currInstr.isSax ? false : true; + if (currInstr.isGuitar) { + if (currInstr.bassGuitar) + setTuning(NOO.tuning(Ttune.Bass4_EADG)); + else if (currInstr.ukulele) + setTuning(NOO.tuning(Ttune.Ukulele_GCEA)); + else + setTuning(NOO.tuning(Ttune.Standard_EADGBE)); + fretsNrSpin.value = currInstr.fretNumber; + tuningCombo.currentIndex = 0; + fretDots.text = currInstr.ukulele ? "5,7,10,12!" : "5,7,9,12!,15,17"; + } else if (currInstr.none) { + setTuning(NOO.tuning(score.scoreObj.lowestNote(), score.scoreObj.highestNote(), NOO.emptyNote(), NOO.emptyNote(), NOO.emptyNote(), NOO.emptyNote())); + } + } + score.ensureVisible(0, 0); + } + } + } - Item { width: NOO.factor(); height: NOO.factor() } - Row { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - Text { - text: instrSel.instrument === 0 ? qsTr("scale of an instrument") : qsTr("tuning", "like a tuning of a guitar or an ukulele") - anchors.verticalCenter: parent.verticalCenter; color: activPal.text - } - TcomboBox { - id: tuningCombo - visible: instrSel.instrument !== 0 - width: NOO.factor() * 22 - model: NOO.tuningModel(instrSel.instrument) - } + + Tile { + visible: instrSel.instrument <= Tinstrument.BassGuitar || instrSel.instrument == Tinstrument.Ukulele + description: instrSel.instrument === 0 ? "" : qsTr("Select appropriate tuning from the list or prepare your own.") + "<br>" + qsTr("Remember to select the appropriate clef in Score settings.") + + Column { + spacing: NOO.factor() + width: parent.width + + Grid { + visible: NOO.instr(instrSel.instrument).isGuitar + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() + columns: parent.width < NOO.factor() * 50 ? 1 : 2 + horizontalItemAlignment: Grid.AlignHCenter + + Row { + spacing: NOO.factor() + + Text { + text: qsTr("number of frets:") + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + } + + TspinBox { + id: fretsNrSpin + + from: 15 + to: 24 + value: GLOB.fretNumber + } + + } + + Row { + visible: !NOO.instr(instrSel.instrument).ukulele + spacing: NOO.factor() + + Text { + text: qsTr("number of strings:") + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + } + + TspinBox { + id: stringNrSpin + + from: 3 + to: 6 + value: GLOB.stringNumber() + } + + } + + } + + Item { + width: NOO.factor() + height: NOO.factor() + } + + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + Text { + text: instrSel.instrument === 0 ? qsTr("scale of an instrument") : qsTr("tuning", "like a tuning of a guitar or an ukulele") + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + } + + TcomboBox { + id: tuningCombo + + visible: instrSel.instrument !== 0 + width: NOO.factor() * 22 + model: NOO.tuningModel(instrSel.instrument) + } + + } + + GlowRect { + height: score.height + width: score.width + NOO.factor() + radius: NOO.factor() / 2 + color: activPal.base + anchors.horizontalCenter: parent.horizontalCenter + + Score { + id: score + + function strNrChanged() { + if (stringNrSpin.value > score.notesCount) { + while (stringNrSpin.value > score.notesCount) { + score.addNote(NOO.note(0, 0, 0, 0)); + score.scoreObj.lastNote.setStringNumber(score.notesCount); + } + tuningCombo.currentIndex = tuningCombo.count - 1; + } else if (stringNrSpin.value < score.notesCount) { + while (stringNrSpin.value < score.notesCount)score.deleteLast() + tuningCombo.currentIndex = tuningCombo.count - 1; + } + } + + function tuningSelected() { + if (tuningCombo.currentIndex < tuningCombo.count - 1) + setTuning(NOO.tuning((currInstr.bassGuitar ? 100 : (currInstr.ukulele ? 110 : 0)) + tuningCombo.currentIndex)); + + } + + anchors.horizontalCenter: parent.horizontalCenter + height: NOO.factor() * 18 + scale: height / firstStaff.linesCount + width: Math.min(instrPage.width * 0.9, NOO.factor() * (instrSel.instrument === 0 ? 14 : 28)) + bgColor: "transparent" + meter: Tmeter.NoMeter + scoreObj.onClicked: tuningCombo.currentIndex = tuningCombo.count - 1 + scoreObj.editMode: true + clef: settings.clef + onClefChanged: settings.clef = clef + Component.onCompleted: { + stringNrSpin.valueModified.connect(strNrChanged); + tuningCombo.activated.connect(tuningSelected); + } + } + + } + + } + + } + + Tile { + description: qsTr("Difference between score notation and real sound pitch.") + + Transposition { + id: transp + } + } - GlowRect { - height: score.height; width: score.width + NOO.factor(); radius: NOO.factor() / 2 - color: activPal.base - anchors.horizontalCenter: parent.horizontalCenter - Score { - id: score - anchors.horizontalCenter: parent.horizontalCenter - height: NOO.factor() * 18 - scale: height / firstStaff.linesCount - width: Math.min(instrPage.width * 0.9, NOO.factor() * (instrSel.instrument === 0 ? 14 : 28)) - bgColor: "transparent" - meter: Tmeter.NoMeter - scoreObj.onClicked: tuningCombo.currentIndex = tuningCombo.count - 1 - scoreObj.editMode: true - clef: settings.clef - onClefChanged: settings.clef = clef - Component.onCompleted: { - stringNrSpin.valueModified.connect(strNrChanged) - tuningCombo.activated.connect(tuningSelected) + + Tile { + description: qsTr("Choose which accidentals will be shown on the staff.") + + ButtonGroup { + buttons: radioRow.children } - function strNrChanged() { - if (stringNrSpin.value > score.notesCount) { - while (stringNrSpin.value > score.notesCount) { - score.addNote(NOO.note(0, 0, 0, 0)) - score.scoreObj.lastNote.setStringNumber(score.notesCount) - } - tuningCombo.currentIndex = tuningCombo.count - 1 - } else if (stringNrSpin.value < score.notesCount) { - while (stringNrSpin.value < score.notesCount) - score.deleteLast() - tuningCombo.currentIndex = tuningCombo.count - 1 - } + + Row { + id: radioRow + + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + TlabelText { + text: qsTr("preferred accidentals:") + } + + TradioButton { + id: prefSharpRadio + + text: qsTr("# - sharps") + checked: !GLOB.preferFlats + } + + TradioButton { + id: prefFlatRadio + + text: qsTr("b - flats") + checked: GLOB.preferFlats + } + } - function tuningSelected() { - if (tuningCombo.currentIndex < tuningCombo.count - 1) - setTuning(NOO.tuning((currInstr.bassGuitar ? 100 : (currInstr.ukulele ? 110 : 0)) + tuningCombo.currentIndex)) + + } + + Tile { + visible: NOO.instr(instrSel.instrument).isGuitar + description: qsTr("As you know, the same note can be played in several places on the fingerboard.<br>If checked, all of them will be shown.") + + TcheckBox { + id: showOtherPosChB + + text: qsTr("show all possibilities of a note") + anchors.horizontalCenter: parent.horizontalCenter } - } + } - } - description: instrSel.instrument === 0 ? "" : qsTr("Select appropriate tuning from the list or prepare your own.") + "<br>" - + qsTr("Remember to select the appropriate clef in Score settings.") - } - Tile { - Transposition { id: transp } - description: qsTr("Difference between score notation and real sound pitch.") - } + Tile { + visible: NOO.instr(instrSel.instrument).isGuitar + description: qsTr("Put numbers of frets marked with dot. Separate the numbers with comma. Add ! (exclamation mark) after a number to paint a dot twice.") - Tile { - ButtonGroup { buttons: radioRow.children } - Row { - id: radioRow - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - TlabelText { text: qsTr("preferred accidentals:") } - TradioButton { id: prefSharpRadio; text: qsTr("# - sharps"); checked: !GLOB.preferFlats } - TradioButton { id: prefFlatRadio; text: qsTr("b - flats"); checked: GLOB.preferFlats } - } - description: qsTr("Choose which accidentals will be shown on the staff.") - } + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter - Tile { - visible: NOO.instr(instrSel.instrument).isGuitar - TcheckBox { - id: showOtherPosChB - text: qsTr("show all possibilities of a note") - anchors.horizontalCenter: parent.horizontalCenter - } - description: qsTr("As you know, the same note can be played in several places on the fingerboard.<br>If checked, all of them will be shown.") - } + Text { + text: qsTr("marked frets", "or frets with dots/marks") + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + } + + TtextField { + id: fretDots + + width: NOO.factor() * 15 + maximumLength: 30 + + validator: RegExpValidator { + regExp: /([1-2]{0,1}[0-9]{1,2}!{0,1},){0,10}/ + } + + } + + } - Tile { - visible: NOO.instr(instrSel.instrument).isGuitar - Row { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - Text { text: qsTr("marked frets", "or frets with dots/marks"); anchors.verticalCenter: parent.verticalCenter; color: activPal.text } - TtextField { - id: fretDots - width: NOO.factor() * 15 - maximumLength: 30 - validator: RegExpValidator { regExp: /([1-2]{0,1}[0-9]{1,2}!{0,1},){0,10}/ } } - } - description: qsTr("Put numbers of frets marked with dot. Separate the numbers with comma. Add ! (exclamation mark) after a number to paint a dot twice.") - } - Tile { - visible: instrSel.instrument !== 0 - Row { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - Text { color: activPal.text; text: qsTr("color of a pointer on an instrument"); anchors.verticalCenter: parent.verticalCenter } - ColorButton { id: fingerColorButt; color: GLOB.fingerColor; title: qsTr("color of a pointer on an instrument") } - } - } - Tile { - visible: instrSel.instrument !== 0 - Row { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - Text { color: activPal.text; text: qsTr("color of a selection"); anchors.verticalCenter: parent.verticalCenter } - ColorButton { id: selectedColorButt; color: GLOB.selectedColor; title: qsTr("color of a selection") } - } - } + Tile { + visible: instrSel.instrument !== 0 + + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + Text { + color: activPal.text + text: qsTr("color of a pointer on an instrument") + anchors.verticalCenter: parent.verticalCenter + } + + ColorButton { + id: fingerColorButt + + color: GLOB.fingerColor + title: qsTr("color of a pointer on an instrument") + } + + } + + } + + Tile { + visible: instrSel.instrument !== 0 + + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + Text { + color: activPal.text + text: qsTr("color of a selection") + anchors.verticalCenter: parent.verticalCenter + } + + ColorButton { + id: selectedColorButt + + color: GLOB.selectedColor + title: qsTr("color of a selection") + } + + } + + } - } - - Timer { // workaround - running: true - interval: 50 - onTriggered: { - initInstr = GLOB.instrument.type - showOtherPosChB.checked = GLOB.showOtherPos - fretDots.text = GLOB.markedFrets - var tmpTrans = GLOB.transposition - instrSel.instrument = GLOB.instrument.type - transp.shift = tmpTrans - if (GLOB.instrument.isGuitar) { - if (GLOB.tuning.type === Ttune.Custom) { - setTuning(NOO.tuning(GLOB.tuning.string(1), GLOB.tuning.string(2), GLOB.tuning.string(3), - GLOB.tuning.string(4), GLOB.tuning.string(5), GLOB.tuning.string(6))) - tuningCombo.currentIndex = tuningCombo.count - 1 - } else { - tuningCombo.currentIndex = GLOB.tuning.type - (GLOB.instrument.bassGuitar ? 100 : (GLOB.instrument.ukulele ? 110 : 0)) - setTuning(NOO.tuning(GLOB.tuning.type)) - } - } else { - setTuning(NOO.tuning(GLOB.tuning.string(1), GLOB.tuning.string(2), - NOO.emptyNote(), NOO.emptyNote(), NOO.emptyNote(), NOO.emptyNote())) - } - first = false - } - } - - function setTuning(t) { - for (var i = 0; i < 6; ++i) { - if (i < t.stringNumber) { - if (i >= score.notesCount) - score.addNote(t.str(i + 1)) - else - score.setNote(i, t.str(i + 1)) - score.scoreObj.note(i).setStringNumber(currInstr.isGuitar ? i + 1 : 0) - } else { - if (score.notesCount > t.stringNr()) - score.deleteLast() - } } - stringNrSpin.value = t.stringNumber - } - - function save() { - GLOB.fingerColor = fingerColorButt.color - GLOB.selectedColor = selectedColorButt.color - GLOB.preferFlats = prefFlatRadio.checked - GLOB.transposition = transp.outShift - var instrChanged = instrSel.instrument !== initInstr - if (NOO.instr(instrSel.instrument).isGuitar) { - GLOB.showOtherPos = showOtherPosChB.checked - GLOB.markedFrets = fretDots.text - var tun - if (tuningCombo.currentIndex === tuningCombo.count - 1) - tun = NOO.tuning(score.scoreObj.noteAt(0), score.scoreObj.noteAt(1), score.scoreObj.noteAt(2), - score.scoreObj.noteAt(3), score.scoreObj.noteAt(4), score.scoreObj.noteAt(5)) - else { - var tunOff = currInstr.bassGuitar ? 100 : (currInstr.ukulele ? 110 : 0) - tun = NOO.tuning(tunOff + tuningCombo.currentIndex) + + // workaround + Timer { + running: true + interval: 50 + onTriggered: { + initInstr = GLOB.instrument.type; + showOtherPosChB.checked = GLOB.showOtherPos; + fretDots.text = GLOB.markedFrets; + var tmpTrans = GLOB.transposition; + instrSel.instrument = GLOB.instrument.type; + transp.shift = tmpTrans; + if (GLOB.instrument.isGuitar) { + if (GLOB.tuning.type === Ttune.Custom) { + setTuning(NOO.tuning(GLOB.tuning.string(1), GLOB.tuning.string(2), GLOB.tuning.string(3), GLOB.tuning.string(4), GLOB.tuning.string(5), GLOB.tuning.string(6))); + tuningCombo.currentIndex = tuningCombo.count - 1; + } else { + tuningCombo.currentIndex = GLOB.tuning.type - (GLOB.instrument.bassGuitar ? 100 : (GLOB.instrument.ukulele ? 110 : 0)); + setTuning(NOO.tuning(GLOB.tuning.type)); + } + } else { + setTuning(NOO.tuning(GLOB.tuning.string(1), GLOB.tuning.string(2), NOO.emptyNote(), NOO.emptyNote(), NOO.emptyNote(), NOO.emptyNote())); + } + first = false; } - // TODO left-handed guitar - // HACK: when instrument changed, set default tuning at first, then real tuning will show scordature, if any - GLOB.setGuitarParams(fretsNrSpin.value, instrChanged ? NOO.tuning(Ttune.Standard_EADGBE) : tun) - GLOB.setInstrument(instrSel.instrument) - if (instrChanged) - GLOB.setGuitarParams(fretsNrSpin.value, tun) - } else { - GLOB.setInstrument(instrSel.instrument) - GLOB.setGuitarParams(0, NOO.defaultScale(instrSel.instrument)) } - GLOB.audioInstrument = instrSel.instrument - SOUND.acceptSettings() - } - - function defaults() { - fingerColorButt.color = Qt.rgba(1, 0, 0.5, 0.78) - selectedColorButt.color = Qt.rgba(0.2, 0.6, 1.0, 1.0) - GLOB.showOtherPos = false - instrSel.instrument = initInstr === 0 ? 7 : 0 - instrSel.instrument = initInstr // switch instrument twice to load its defaults - fretDots.text = currInstr.ukulele ? "5,7,10,12!" : "5,7,9,12!,15,17" - } - - function help() { NOO.openDocLink("instrument-settings/") } + + ScrollBar.vertical: ScrollBar { + active: false + visible: active + } + } diff --git a/src/qml/settings/KeySufixEdit.qml b/src/qml/settings/KeySufixEdit.qml index dfb6766202994cf2a8ae44ea07c5ed5d2764d122..d4f26848768bdce95b6ea59b52e7fbb835c89688 100644 --- a/src/qml/settings/KeySufixEdit.qml +++ b/src/qml/settings/KeySufixEdit.qml @@ -2,49 +2,60 @@ * 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 Nootka 1.0 -import "../" +Column { + property alias sufix: sufixField.text + property int noteOne: 3 + property int alterOne: 0 + property int noteTwo: 7 + property int alterTwo: -1 + property int nameStyle: 0 + spacing: NOO.factor() / 2 + + Text { + wrapMode: Text.NoWrap + horizontalAlignment: Text.AlignHCenter + text: qsTranslate("TscoreSettings", "in the major keys:") + anchors.horizontalCenter: parent.horizontalCenter + color: enabled ? activPal.text : disdPal.text + } + + TtextField { + id: sufixField + + width: NOO.factor() * 8 + maximumLength: 10 + horizontalAlignment: TextInput.AlignHCenter + anchors.horizontalCenter: parent.horizontalCenter + } + + Item { + height: NOO.factor() / 2 + width: 1 + } + + Text { + text: qsTranslate("TscoreSettings", "for example") + ":" + anchors.horizontalCenter: parent.horizontalCenter + color: enabled ? activPal.text : disdPal.text + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + color: enabled ? activPal.text : disdPal.text + text: NOO.noteName(NOO.note(noteOne, 0, alterOne), nameStyle, false) + (sufix === "" || sufix === " " ? "" : "-" + sufixField.text) + "\n" + NOO.noteName(NOO.note(noteTwo, 0, alterTwo), nameStyle, false) + (sufix === "" || sufix === " " ? "" : "-" + sufixField.text) + + font { + bold: true + pixelSize: NOO.factor() * 1.5 + } + + } -Column { - property alias sufix: sufixField.text - property int noteOne: 3 - property int alterOne: 0 - property int noteTwo: 7 - property int alterTwo: -1 - property int nameStyle: 0 - - spacing: NOO.factor() / 2 - - Text { - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignHCenter - text: qsTranslate("TscoreSettings", "in the major keys:") - anchors.horizontalCenter: parent.horizontalCenter - color: enabled ? activPal.text : disdPal.text - } - TtextField { - width: NOO.factor() * 8 - id: sufixField - maximumLength: 10 - horizontalAlignment: TextInput.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - } - Item { height: NOO.factor() / 2; width: 1 } - Text { - text: qsTranslate("TscoreSettings", "for example") + ":" - anchors.horizontalCenter: parent.horizontalCenter - color: enabled ? activPal.text : disdPal.text - } - Text { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - color: enabled ? activPal.text : disdPal.text - font { bold: true; pixelSize: NOO.factor() * 1.5 } - text: NOO.noteName(NOO.note(noteOne, 0, alterOne), nameStyle, false) + (sufix === "" || sufix === " " ? "" : "-" + sufixField.text) + "\n" - + NOO.noteName(NOO.note(noteTwo, 0, alterTwo), nameStyle, false) + (sufix === "" || sufix === " " ? "" : "-" + sufixField.text) - } } diff --git a/src/qml/settings/MiddleA440.qml b/src/qml/settings/MiddleA440.qml index ebfa9fd982f78fa6d0a6f59c4ca7ea84101980ee..413fed6330916d157d6590dfb1191d55f9ce355b 100644 --- a/src/qml/settings/MiddleA440.qml +++ b/src/qml/settings/MiddleA440.qml @@ -2,51 +2,74 @@ * 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 Nootka 1.0 -import "../" - Tile { - property alias value: freqSpin.value - property bool showDesc: true - - description: !showDesc ? "" : - qsTranslate("SoundPage", "The base frequency of <i>middle a</i>.<br>Detection of the proper pitch of notes is relative to this value. This also affects the pitch of played sounds.") - Column { - width: parent.width - Row { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - TlabelText { text: qsTranslate("SoundPage", "middle A") } - Text { // staff - height: NOO.factor() * 4.5 - y: NOO.factor() * -1.6 - font { pixelSize: NOO.factor() * 2.5; family: "scorek" } - text: "\ue014\ue014\ue014\ue014" - color: enabled ? activPal.text : disdPal.text - Text { // clef - x: NOO.factor() / 4 - y: NOO.factor() * -0.6 - color: parent.color - font: parent.font - text: "\ue050" - } - Text { // note - color: parent.color - font: parent.font - x: NOO.factor() * 2.7 - y: NOO.factor() * -0.9 - text: "\ue1d7" + property alias value: freqSpin.value + property bool showDesc: true + + description: !showDesc ? "" : qsTranslate("SoundPage", "The base frequency of <i>middle a</i>.<br>Detection of the proper pitch of notes is relative to this value. This also affects the pitch of played sounds.") + + Column { + width: parent.width + + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + TlabelText { + text: qsTranslate("SoundPage", "middle A") + } + // staff + + Text { + height: NOO.factor() * 4.5 + y: NOO.factor() * -1.6 + text: "\ue014\ue014\ue014\ue014" + color: enabled ? activPal.text : disdPal.text + + font { + pixelSize: NOO.factor() * 2.5 + family: "scorek" + } + + // clef + Text { + x: NOO.factor() / 4 + y: NOO.factor() * -0.6 + color: parent.color + font: parent.font + text: "\ue050" + } + + // note + Text { + color: parent.color + font: parent.font + x: NOO.factor() * 2.7 + y: NOO.factor() * -0.9 + text: "\ue1d7" + } + + } + + TspinBox { + id: freqSpin + + anchors.verticalCenter: parent.verticalCenter + from: 391 // in range of two semitones up and down around middle A (440Hz) + to: 493 + } + + TlabelText { + text: qsTranslate("SoundPage", "[Hz]") + } + } - } - TspinBox { - id: freqSpin - anchors.verticalCenter: parent.verticalCenter; - from: 391; to: 493 // in range of two semitones up and down around middle A (440Hz) - } - TlabelText { text: qsTranslate("SoundPage", "[Hz]") } + } - } + } diff --git a/src/qml/settings/ScorePage.qml b/src/qml/settings/ScorePage.qml index fb887132b3e238184d06a2c3aee2b679c08013c1..1e39f10107d4f4a80aa9c11d09c9cd41ab959b7d 100644 --- a/src/qml/settings/ScorePage.qml +++ b/src/qml/settings/ScorePage.qml @@ -2,326 +2,461 @@ * 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.Layouts 1.3 - -import Nootka 1.0 import Score 1.0 -import "../" - Column { - width: parent.width; height: parent.height + function save() { + var prevSingleMode = GLOB.singleNoteMode; + GLOB.singleNoteMode = singleNoteModeChB.checked; + if (singleNoteModeChB.checked) { + GLOB.showEnharmNotes = showEnharmNotesChB.checked; + GLOB.enharmNoteColor = enharmNoteColor.color; + } else if (prevSingleMode != GLOB.singleNoteMode) { + NOO.mainScore.scoreObj.editMode = true; + } + GLOB.rhythmsEnabled = rhythmsEnabledChB.checked; + GLOB.enableDoubleAccids = doubleAccidsChB.checked; + GLOB.noteCursorColor = pointerColorButt.color; + GLOB.keySignatureEnabled = enableKeyChB.checked; + GLOB.scientificOctaves = scientificRadio.checked; + GLOB.noteNameStyle = nameStyleSel.style; + GLOB.seventhIsB = is7BSelector.is7B; + GLOB.namesOnScore = namesOnScoreChB.checked; + GLOB.nameColor = nameColorButt.color; + // GLOB.clefType saved in TsettingsDialog.qml + if (GLOB.keySignatureEnabled) { + GLOB.showKeyName = showKeyNamesChB.checked; + if (GLOB.showKeyName) { + GLOB.majorKeyNameSufix = majKeySufixText.sufix; + GLOB.minorKeyNameSufix = minKeySufixText.sufix; + GLOB.keyNameStyle = keyNameStyleSel.style; + GLOB.updateKeySignatureNames(); + } + } + } + + function defaults() { + singleNoteModeChB.checked = false; + showEnharmNotesChB.checked = false; + enharmNoteColor.color = Qt.rgba(0, 0.635294, 0.635294, 1); + doubleAccidsChB.checked = false; + pointerColorButt.color = "pink"; + settings.clef = GLOB.instrument.clef; + enableKeyChB.checked = false; + musicalRadio.checked = true; + } + + function help() { + NOO.openDocLink("2017/05/17/score-settings/"); + } + + width: parent.width + height: parent.height TbuttonBar { - id: headList - model: [ qsTr("Score settings"), qsTr("Key signatures"), qsTr("Clefs"), qsTr("Notes naming") ] - onCurrentIndexChanged: swipePages.currentIndex = currentIndex + id: headList + + model: [qsTr("Score settings"), qsTr("Key signatures"), qsTr("Clefs"), qsTr("Notes naming")] + onCurrentIndexChanged: swipePages.currentIndex = currentIndex } StackLayout { - id: swipePages - height: parent.height - headList.height - width: parent.width - - Tflickable { // 1st page (general) - height: parent.height - contentHeight: firstColumn.height + NOO.factor() * 2 - contentWidth: Math.max(width, NOO.factor() * 35) - Column { - id: firstColumn - width: parent.width - spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 - Tframe { - width: parent.width * 0.99 - anchors.horizontalCenter: parent.horizontalCenter + id: swipePages + + height: parent.height - headList.height + width: parent.width + + // 1st page (general) + Tflickable { + height: parent.height + contentHeight: firstColumn.height + NOO.factor() * 2 + contentWidth: Math.max(width, NOO.factor() * 35) + Component.onCompleted: enharmNoteColor.color = GLOB.enharmNoteColor + Column { - spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 - width: parent.width - Tile { - description: qsTr("When enabled, a score displays only a single note.") - TcheckBox { - id: singleNoteModeChB - text: qsTr("use single note only") - checked: GLOB.singleNoteMode - anchors.horizontalCenter: parent.horizontalCenter + id: firstColumn + + width: parent.width + spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 + + Tframe { + width: parent.width * 0.99 + anchors.horizontalCenter: parent.horizontalCenter + + Column { + spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 + width: parent.width + + Tile { + description: qsTr("When enabled, a score displays only a single note.") + + TcheckBox { + id: singleNoteModeChB + + text: qsTr("use single note only") + checked: GLOB.singleNoteMode + anchors.horizontalCenter: parent.horizontalCenter + } + + } + + Tile { + enabled: singleNoteModeChB.checked + description: qsTr("Shows enharmonic variants of notes.<br>i.e.: the note E is also Fb (F flat) <i>and</i> Dx (D with double sharp).") + + TcheckBox { + id: showEnharmNotesChB + + checked: GLOB.showEnharmNotes + text: qsTr("show enharmonic variants of notes") + anchors.horizontalCenter: parent.horizontalCenter + } + + } + + Tile { + enabled: singleNoteModeChB.checked + + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + TlabelText { + text: qsTr("color of enharmonic notes") + } + + ColorButton { + id: enharmNoteColor + + title: qsTr("color of enharmonic notes") + } + + } + + } + + } + } - } - Tile { - enabled: singleNoteModeChB.checked - description: qsTr("Shows enharmonic variants of notes.<br>i.e.: the note E is also Fb (F flat) <i>and</i> Dx (D with double sharp).") - TcheckBox { - id: showEnharmNotesChB - checked: GLOB.showEnharmNotes - text: qsTr("show enharmonic variants of notes") - anchors.horizontalCenter: parent.horizontalCenter + Tile { + description: qsTr("Use rhythms or only bare note heads.") + enabled: !singleNoteModeChB.checked + + TcheckBox { + id: rhythmsEnabledChB + + text: qsTr("enable rhythms") + anchors.horizontalCenter: parent.horizontalCenter + checked: GLOB.rhythmsEnabled + } + } - } - Tile { - enabled: singleNoteModeChB.checked - Row { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - TlabelText { text: qsTr("color of enharmonic notes") } - ColorButton { id: enharmNoteColor; title: qsTr("color of enharmonic notes") } + + Tile { + description: qsTr("If checked, you can use double sharps and double flats.") + + TcheckBox { + id: doubleAccidsChB + + text: qsTr("use double accidentals") + anchors.horizontalCenter: parent.horizontalCenter + checked: GLOB.enableDoubleAccids + } + } - } - } - } - Tile { - description: qsTr("Use rhythms or only bare note heads.") - enabled: !singleNoteModeChB.checked - TcheckBox { - id: rhythmsEnabledChB - text: qsTr("enable rhythms") - anchors.horizontalCenter: parent.horizontalCenter - checked: GLOB.rhythmsEnabled - } - } - Tile { - description: qsTr("If checked, you can use double sharps and double flats.") - TcheckBox { - id: doubleAccidsChB - text: qsTr("use double accidentals") - anchors.horizontalCenter: parent.horizontalCenter - checked: GLOB.enableDoubleAccids - } - } - Tile { - Row { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - TlabelText { text: qsTr("note-cursor color") } - ColorButton { id: pointerColorButt; color: GLOB.noteCursorColor; title: qsTr("note-cursor color") } + + Tile { + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + TlabelText { + text: qsTr("note-cursor color") + } + + ColorButton { + id: pointerColorButt + + color: GLOB.noteCursorColor + title: qsTr("note-cursor color") + } + + } + + } + } - } + } - Component.onCompleted: enharmNoteColor.color = GLOB.enharmNoteColor - } + // 2nd page (key signatures) + Tflickable { + height: parent.height + contentHeight: secondColumn.height + NOO.factor() * 2 + contentWidth: Math.max(width, NOO.factor() * 35) - Tflickable { // 2nd page (key signatures) - height: parent.height - contentHeight: secondColumn.height + NOO.factor() * 2 - contentWidth: Math.max(width, NOO.factor() * 35) - Column { - id: secondColumn - width: parent.width - spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 - TcheckBox { - id: enableKeyChB - text: qsTr("use key signatures") - anchors.horizontalCenter: parent.horizontalCenter - checked: GLOB.keySignatureEnabled - } - Tframe { - width: parent.width * 0.99 - anchors.horizontalCenter: parent.horizontalCenter Column { - spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 - width: parent.width - Tile { - enabled: enableKeyChB.checked + id: secondColumn + + width: parent.width + spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 + TcheckBox { - id: showKeyNamesChB - text: qsTr("show names of key signature") - anchors.horizontalCenter: parent.horizontalCenter - checked: GLOB.showKeyName + id: enableKeyChB + + text: qsTr("use key signatures") + anchors.horizontalCenter: parent.horizontalCenter + checked: GLOB.keySignatureEnabled } - } - - Tile { - enabled: enableKeyChB.checked && showKeyNamesChB.checked - Grid { - columns: parent.width < NOO.factor() * 50 ? 1 : 2 - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - horizontalItemAlignment: Grid.AlignHCenter - NameStyleSelector { - id: keyNameStyleSel - seventhIsB: is7BSelector.is7B - } - Column { - Text { - text: qsTr("Naming extension") - anchors.horizontalCenter: parent.horizontalCenter - color: enabled ? activPal.text : disdPal.text - } - Row { - spacing: NOO.factor() * 2 - anchors.horizontalCenter: parent.horizontalCenter - KeySufixEdit { id: majKeySufixText; nameStyle: keyNameStyleSel.style } - KeySufixEdit { id: minKeySufixText; nameStyle: keyNameStyleSel.style; noteOne: 1; alterOne: 1; noteTwo: 5; alterTwo: 0 } + + Tframe { + width: parent.width * 0.99 + anchors.horizontalCenter: parent.horizontalCenter + + Column { + spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 + width: parent.width + + Tile { + enabled: enableKeyChB.checked + + TcheckBox { + id: showKeyNamesChB + + text: qsTr("show names of key signature") + anchors.horizontalCenter: parent.horizontalCenter + checked: GLOB.showKeyName + } + + } + + Tile { + enabled: enableKeyChB.checked && showKeyNamesChB.checked + Component.onCompleted: { + majKeySufixText.sufix = GLOB.majorKeyNameSufix; + minKeySufixText.sufix = GLOB.minorKeyNameSufix; + keyNameStyleSel.style = GLOB.keyNameStyle; + } + + Grid { + columns: parent.width < NOO.factor() * 50 ? 1 : 2 + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + horizontalItemAlignment: Grid.AlignHCenter + + NameStyleSelector { + id: keyNameStyleSel + + seventhIsB: is7BSelector.is7B + } + + Column { + Text { + text: qsTr("Naming extension") + anchors.horizontalCenter: parent.horizontalCenter + color: enabled ? activPal.text : disdPal.text + } + + Row { + spacing: NOO.factor() * 2 + anchors.horizontalCenter: parent.horizontalCenter + + KeySufixEdit { + id: majKeySufixText + + nameStyle: keyNameStyleSel.style + } + + KeySufixEdit { + id: minKeySufixText + + nameStyle: keyNameStyleSel.style + noteOne: 1 + alterOne: 1 + noteTwo: 5 + alterTwo: 0 + } + + } + + } + + } + + } + } - } - } - Component.onCompleted: { - majKeySufixText.sufix = GLOB.majorKeyNameSufix - minKeySufixText.sufix = GLOB.minorKeyNameSufix - keyNameStyleSel.style = GLOB.keyNameStyle + } - } - } - } - } - } + } - Column { // 3rd page (clefs) - width: parent.width - spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 - Text { - id: clefText - text: qsTr("Select default clef for the application.") + "<br><b>" - + qsTr("Remember! Not all clefs are suitable for some possible tunings or instrument types!") + "<b>" - textFormat: Text.StyledText - horizontalAlignment: Text.AlignHCenter - width: parent.width - wrapMode: Text.WordWrap - color: activPal.text - } - ClefMenu { - id: clefs - width: parent.width; height: swipePages.height - parent.spacing - clefText.height - selClef: settings.clef - onSelClefChanged: settings.clef = selClef } - } - Tflickable { // 4rd page (note name calling) - contentHeight: nameCol.height + NOO.factor() * 2 - contentWidth: Math.max(width, NOO.factor() * 35) + // 3rd page (clefs) Column { - id: nameCol - width: parent.width - spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 - anchors.horizontalCenter: parent.horizontalCenter - Tile { - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() - TcheckBox { - id: namesOnScoreChB - text: qsTr("Show names of all notes on the score") - anchors.horizontalCenter: parent.horizontalCenter - checked: GLOB.namesOnScore - } - Row { - spacing: NOO.factor() - enabled: namesOnScoreChB.checked - anchors.horizontalCenter: parent.horizontalCenter - TlabelText { text: qsTr("names highlight color") } - ColorButton { id: nameColorButt; color: GLOB.nameColor; title: qsTr("names highlight color") } - } + width: parent.width + spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 + + Text { + id: clefText + + text: qsTr("Select default clef for the application.") + "<br><b>" + qsTr("Remember! Not all clefs are suitable for some possible tunings or instrument types!") + "<b>" + textFormat: Text.StyledText + horizontalAlignment: Text.AlignHCenter + width: parent.width + wrapMode: Text.WordWrap + color: activPal.text } - } - Tile { - description: qsTr("Naming style of note. The main difference is the 7th note.<br>Is it B and B flat, or H and B?") - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() * 2 - Select7note { - id: is7BSelector - anchors.horizontalCenter: parent.horizontalCenter - style: nameStyleSel.style - } - NameStyleSelector { - id: nameStyleSel - seventhIsB: is7BSelector.is7B - anchors.horizontalCenter: parent.horizontalCenter - } + + ClefMenu { + id: clefs + + width: parent.width + height: swipePages.height - parent.spacing - clefText.height + selClef: settings.clef + onSelClefChanged: settings.clef = selClef } - } - Tile { - ButtonGroup { id: octaveGr } + + } + + // 4rd page (note name calling) + Tflickable { + contentHeight: nameCol.height + NOO.factor() * 2 + contentWidth: Math.max(width, NOO.factor() * 35) + Column { - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width * 0.9 - spacing: NOO.factor() - Row { + id: nameCol + + width: parent.width + spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() * 2 - Text { anchors.verticalCenter: parent.verticalCenter; text: qsTr("Octave numbers"); color: activPal.text } - TradioButton { - id: scientificRadio - text: qsTr("scientific") - ButtonGroup.group: octaveGr - checked: GLOB.scientificOctaves + Component.onCompleted: { + nameStyleSel.style = GLOB.noteNameStyle; + is7BSelector.is7B = GLOB.seventhIsB; + } + + Tile { + Column { + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() + + TcheckBox { + id: namesOnScoreChB + + text: qsTr("Show names of all notes on the score") + anchors.horizontalCenter: parent.horizontalCenter + checked: GLOB.namesOnScore + } + + Row { + spacing: NOO.factor() + enabled: namesOnScoreChB.checked + anchors.horizontalCenter: parent.horizontalCenter + + TlabelText { + text: qsTr("names highlight color") + } + + ColorButton { + id: nameColorButt + + color: GLOB.nameColor + title: qsTr("names highlight color") + } + + } + + } + } - TradioButton { - id: musicalRadio - text: qsTr("musical") - ButtonGroup.group: octaveGr - checked: !GLOB.scientificOctaves + + Tile { + description: qsTr("Naming style of note. The main difference is the 7th note.<br>Is it B and B flat, or H and B?") + + Column { + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() * 2 + + Select7note { + id: is7BSelector + + anchors.horizontalCenter: parent.horizontalCenter + style: nameStyleSel.style + } + + NameStyleSelector { + id: nameStyleSel + + seventhIsB: is7BSelector.is7B + anchors.horizontalCenter: parent.horizontalCenter + } + + } + } - } - Text { - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.text; textFormat: Text.RichText - text: "<table>" - + "<tr><td> <b>"+ NOO.TR("TnameItem", "Octaves") + ":</b> </td><td> <b>" + qsTr("scientific") + "</b> </td><td> <b>" + qsTr("musical") + "</b> </td></tr>" - + "<tr><td>"+ NOO.TR("TnoteName", "Subcontra octave") + "</td><td align=\"center\">C<sub>0</sub></td><td align=\"center\">C<sub>2</sub></td></tr>" - + "<tr><td>"+ NOO.TR("TnoteName", "Contra octave") + "</td><td align=\"center\">C<sub>1</sub></td><td align=\"center\">C<sub>1</sub></td></tr>" - + "<tr><td>"+ NOO.TR("TnoteName", "Great octave") + "</td><td align=\"center\">C<sub>2</sub></td><td align=\"center\">C</td></tr>" - + "<tr><td>"+ NOO.TR("TnoteName", "Small octave") + "</td><td align=\"center\">C<sub>3</sub></td><td align=\"center\">c</td></tr>" - + "<tr><td>"+ NOO.TR("TnoteName", "One-line octave") + "</td><td align=\"center\">C<sub>4</sub></td><td align=\"center\">c<sup>1</sup></td></tr>" - + "<tr><td>"+ NOO.TR("TnoteName", "Two-line octave") + "</td><td align=\"center\">C<sub>5</sub></td><td align=\"center\">c<sup>2</sup></td></tr>" - + "</table>" - } - } - description: qsTr("Scientific (international) pitch notation is widely used in technical sources and tuning devices/applications, when the other notation style is used more in music publications.") - } - Component.onCompleted: { - nameStyleSel.style = GLOB.noteNameStyle - is7BSelector.is7B = GLOB.seventhIsB - } - } - } - } + Tile { + description: qsTr("Scientific (international) pitch notation is widely used in technical sources and tuning devices/applications, when the other notation style is used more in music publications.") + + ButtonGroup { + id: octaveGr + } + + Column { + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width * 0.9 + spacing: NOO.factor() + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() * 2 + + Text { + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Octave numbers") + color: activPal.text + } + + TradioButton { + id: scientificRadio + + text: qsTr("scientific") + ButtonGroup.group: octaveGr + checked: GLOB.scientificOctaves + } + + TradioButton { + id: musicalRadio + + text: qsTr("musical") + ButtonGroup.group: octaveGr + checked: !GLOB.scientificOctaves + } + + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + textFormat: Text.RichText + text: "<table>" + "<tr><td> <b>" + NOO.TR("TnameItem", "Octaves") + ":</b> </td><td> <b>" + qsTr("scientific") + "</b> </td><td> <b>" + qsTr("musical") + "</b> </td></tr>" + "<tr><td>" + NOO.TR("TnoteName", "Subcontra octave") + "</td><td align=\"center\">C<sub>0</sub></td><td align=\"center\">C<sub>2</sub></td></tr>" + "<tr><td>" + NOO.TR("TnoteName", "Contra octave") + "</td><td align=\"center\">C<sub>1</sub></td><td align=\"center\">C<sub>1</sub></td></tr>" + "<tr><td>" + NOO.TR("TnoteName", "Great octave") + "</td><td align=\"center\">C<sub>2</sub></td><td align=\"center\">C</td></tr>" + "<tr><td>" + NOO.TR("TnoteName", "Small octave") + "</td><td align=\"center\">C<sub>3</sub></td><td align=\"center\">c</td></tr>" + "<tr><td>" + NOO.TR("TnoteName", "One-line octave") + "</td><td align=\"center\">C<sub>4</sub></td><td align=\"center\">c<sup>1</sup></td></tr>" + "<tr><td>" + NOO.TR("TnoteName", "Two-line octave") + "</td><td align=\"center\">C<sub>5</sub></td><td align=\"center\">c<sup>2</sup></td></tr>" + "</table>" + } + + } + + } + + } - function save() { - var prevSingleMode = GLOB.singleNoteMode - GLOB.singleNoteMode = singleNoteModeChB.checked - if (singleNoteModeChB.checked) { - GLOB.showEnharmNotes = showEnharmNotesChB.checked - GLOB.enharmNoteColor = enharmNoteColor.color - } else if (prevSingleMode != GLOB.singleNoteMode) - NOO.mainScore.scoreObj.editMode = true - GLOB.rhythmsEnabled = rhythmsEnabledChB.checked - GLOB.enableDoubleAccids = doubleAccidsChB.checked - GLOB.noteCursorColor = pointerColorButt.color - GLOB.keySignatureEnabled = enableKeyChB.checked - GLOB.scientificOctaves = scientificRadio.checked - GLOB.noteNameStyle = nameStyleSel.style - GLOB.seventhIsB = is7BSelector.is7B - GLOB.namesOnScore = namesOnScoreChB.checked - GLOB.nameColor = nameColorButt.color - // GLOB.clefType saved in TsettingsDialog.qml - if (GLOB.keySignatureEnabled) { - GLOB.showKeyName = showKeyNamesChB.checked - if (GLOB.showKeyName) { - GLOB.majorKeyNameSufix = majKeySufixText.sufix - GLOB.minorKeyNameSufix = minKeySufixText.sufix - GLOB.keyNameStyle = keyNameStyleSel.style - GLOB.updateKeySignatureNames() } - } - } - function defaults() { - singleNoteModeChB.checked = false - showEnharmNotesChB.checked = false - enharmNoteColor.color = Qt.rgba(0, 0.6352941176470588, 0.6352941176470588, 1) - doubleAccidsChB.checked = false - pointerColorButt.color = "pink" - settings.clef = GLOB.instrument.clef - - enableKeyChB.checked = false - musicalRadio.checked = true } - function help() { NOO.openDocLink("2017/05/17/score-settings/") } } diff --git a/src/qml/settings/Select7note.qml b/src/qml/settings/Select7note.qml index d820bb89434a82ad9f6bc8b0f3cefbb20d62fa74..959fa506c7fde24e4e68a2815c7009d96f802fcc 100644 --- a/src/qml/settings/Select7note.qml +++ b/src/qml/settings/Select7note.qml @@ -2,50 +2,68 @@ * 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 Nootka 1.0 -import "../" - - Item { - property alias is7B: bButt.checked - property int style: -1 - - width: mainLay.width - height: mainLay.height - - Grid { - id: mainLay - columns: 2 - spacing: NOO.factor() - verticalItemAlignment: Grid.AlignVCenter - - ButtonGroup { buttons: butRow.children } - Row { - id: butRow - y: (parent.height - height) / 2 - spacing: NOO.factor() / 2 - Text { text: qsTr("7th note is:"); color: enabled ? activPal.text : disdPal.text; anchors.verticalCenter: parent.verticalCenter } - TradioButton { id: bButt; text: "B" } - TradioButton { text: "H"; checked: !bButt.checked } - } + property alias is7B: bButt.checked + property int style: -1 - Text { - id: preview - font.pixelSize: NOO.factor() * 2 - color: activPal.text + width: mainLay.width + height: mainLay.height + onStyleChanged: { + if (style > -1) { + var sp = ""; + for (var n = 1; n < 8; ++n) sp += NOO.noteName(NOO.note(n, 1, 0), style, false) + " " + preview.text = sp; + } } - } - - onStyleChanged: { - if (style > -1) { - var sp = "" - for (var n = 1; n < 8; ++n) - sp += NOO.noteName(NOO.note(n, 1, 0), style, false) + " " - preview.text = sp + + Grid { + id: mainLay + + columns: 2 + spacing: NOO.factor() + verticalItemAlignment: Grid.AlignVCenter + + ButtonGroup { + buttons: butRow.children + } + + Row { + id: butRow + + y: (parent.height - height) / 2 + spacing: NOO.factor() / 2 + + Text { + text: qsTr("7th note is:") + color: enabled ? activPal.text : disdPal.text + anchors.verticalCenter: parent.verticalCenter + } + + TradioButton { + id: bButt + + text: "B" + } + + TradioButton { + text: "H" + checked: !bButt.checked + } + + } + + Text { + id: preview + + font.pixelSize: NOO.factor() * 2 + color: activPal.text + } + } - } -} +} diff --git a/src/qml/settings/SoundPage.qml b/src/qml/settings/SoundPage.qml index 19616941b58d9d321783813071a44ce4ba4c19ce..8868c32a352f773d9bda79ab10dba4ffd255484e 100644 --- a/src/qml/settings/SoundPage.qml +++ b/src/qml/settings/SoundPage.qml @@ -2,302 +2,407 @@ * 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.Layouts 1.3 -import Nootka 1.0 -import "../" - - Column { - width: parent.width; height: parent.height + function save() { + if (enableInChB.checked) { + GLOB.inDevName = inDevCombo.currentText; + GLOB.minDuration = minDurSpin.value / 1000; + GLOB.minVolume = volSpin.value / 100; + GLOB.detectionMethod = methodCombo.currentIndex; + GLOB.useFilter = noiseFilterChB.checked; + GLOB.midAfreq = freqSpin.value; + GLOB.JACKorASIO = jackInChB.checked; + } + GLOB.audioInEnabled = enableInChB.checked; + if (enableOutChB.checked) { + GLOB.outDevName = outDevCombo.currentText; + GLOB.forwardInput = forwardInChB.checked; + } + GLOB.audioOutEnabled = enableOutChB.checked; + SOUND.acceptSettings(); + } + + function defaults() { + enableInChB.checked = true; + inDevCombo.currentIndex = 0; + minDurSpin.value = 150; + volSpin.value = 40; + freqSpin.value = 440; + methodCombo.currentIndex = 2; + noiseFilterChB.checked = true; + freqSpin.value = 440; + jackInChB.checked = false; + enableOutChB.checked = true; + outDevCombo.currentIndex = 0; + forwardInChB.checked = false; + } - TbuttonBar { - id: headList - model: [ qsTr("listening"), qsTr("playing") ] - onCurrentIndexChanged: stack.currentIndex = currentIndex - } + function help() { + NOO.openDocLink("2017/05/17/audio-settings/"); + } - StackLayout { - id: stack - height: parent.height - headList.height - NOO.factor() / 2 width: parent.width - currentIndex: -1 + height: parent.height + Component.onCompleted: { + if (inDevCombo.currentIndex === -1) + inDevCombo.model = qsTr("no devices found"); + else + inDevCombo.currentIndex = inDevCombo.find(SOUND.currentInDevName()); + minDurSpin.value = Math.ceil(GLOB.minDuration * 1000); + methodCombo.currentIndex = GLOB.detectionMethod; + noiseFilterChB.checked = GLOB.useFilter; + enableInChB.checked = GLOB.audioInEnabled; + jackInChB.checked = GLOB.JACKorASIO; + if (outDevCombo.currentIndex === -1) + outDevCombo.model = qsTr("no devices found"); + else + outDevCombo.currentIndex = outDevCombo.find(SOUND.currentOutDevName()); + forwardInChB.checked = GLOB.forwardInput; + enableOutChB.checked = GLOB.audioOutEnabled; + } + + TbuttonBar { + id: headList + + model: [qsTr("listening"), qsTr("playing")] + onCurrentIndexChanged: stack.currentIndex = currentIndex + } - Tflickable { // "listening" page - contentHeight: inCol.height + NOO.factor() * 2 - contentWidth: width + StackLayout { + id: stack - Column { - id: inCol + height: parent.height - headList.height - NOO.factor() / 2 width: parent.width - topPadding: NOO.isAndroid() ? 2 : NOO.factor() / 2 + currentIndex: -1 - TcheckBox { - id: enableInChB - text: qsTr("enable pitch detection") - anchors.horizontalCenter: parent.horizontalCenter - checked: true - } + // "listening" page + Tflickable { + contentHeight: inCol.height + NOO.factor() * 2 + contentWidth: width + + Column { + // Column + + id: inCol + + width: parent.width + topPadding: NOO.isAndroid() ? 2 : NOO.factor() / 2 + + TcheckBox { + id: enableInChB - Column { - enabled: enableInChB.checked - width: parent.width - spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 - - Tile { - description: qsTr("Be sure your input device (microphone, webcam, instrument, etc.) is plugged in, properly configured, and working.") - Row { - spacing: NOO.factor() * 2 - anchors.horizontalCenter: parent.horizontalCenter - TlabelText { text: qsTr("input device"); anchors.verticalCenter: parent.verticalCenter } - TcomboBox { - id: inDevCombo - anchors.verticalCenter: parent.verticalCenter - width: NOO.factor() * 20 - model: SOUND.inputDevices() - } - TcheckBox { - visible: !NOO.isAndroid() && !NOO.isMac() - id: jackInChB - text: NOO.isWindows() ? "ASIO" : "JACK" - anchors.verticalCenter: parent.verticalCenter - onCheckedChanged: { - SOUND.setJACKorASIO(jackInChB.checked) - inDevCombo.model = SOUND.inputDevices() - outDevCombo.model = SOUND.outputDevices() + text: qsTr("enable pitch detection") + anchors.horizontalCenter: parent.horizontalCenter + checked: true } - } - } - } - - Tile { - description: qsTr("Only sounds longer than the selected time will be pitch-detected.<br>Selecting a longer minimum note duration helps avoid capturing fret noise or other unexpected sounds but decreases responsiveness.") - Row { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - TlabelText { text: qsTr("minimum note duration") } - TspinBox { - id: minDurSpin - from: settings.instrument !== 3 ? 80 : 160 // longer note if bass - to: 1000 - stepSize: 10 - editable: true - } - TlabelText { text: qsTr("[milliseconds]") } - } - } - - Tile { - description: qsTr("Minimum volume of a sound to be pitch-detected") - Row { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - Text { text: qsTr("minimum volume"); anchors.verticalCenter: parent.verticalCenter; color: enabled ? activPal.text : disdPal.text } - Tslider { - anchors.verticalCenter: parent.verticalCenter - width: Math.min(NOO.factor() * 15, parent.parent.width / 3) - from: 10; to: 80 - value: volSpin.value - onValueChanged: volSpin.value = value - stepSize: 5 - } - TspinBox { - id: volSpin - from: 10; to: 80 - value: Math.ceil(GLOB.minVolume * 100) - editable: true - } - TlabelText { text: "%" } - } - } - MiddleA440 { - id: freqSpin - value: GLOB.midAfreq - } + Column { + enabled: enableInChB.checked + width: parent.width + spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 + + Tile { + description: qsTr("Be sure your input device (microphone, webcam, instrument, etc.) is plugged in, properly configured, and working.") + + Row { + spacing: NOO.factor() * 2 + anchors.horizontalCenter: parent.horizontalCenter + + TlabelText { + text: qsTr("input device") + anchors.verticalCenter: parent.verticalCenter + } + + TcomboBox { + id: inDevCombo + + anchors.verticalCenter: parent.verticalCenter + width: NOO.factor() * 20 + model: SOUND.inputDevices() + } + + TcheckBox { + id: jackInChB + + visible: !NOO.isAndroid() && !NOO.isMac() + text: NOO.isWindows() ? "ASIO" : "JACK" + anchors.verticalCenter: parent.verticalCenter + onCheckedChanged: { + SOUND.setJACKorASIO(jackInChB.checked); + inDevCombo.model = SOUND.inputDevices(); + outDevCombo.model = SOUND.outputDevices(); + } + } + + } + + } + + Tile { + description: qsTr("Only sounds longer than the selected time will be pitch-detected.<br>Selecting a longer minimum note duration helps avoid capturing fret noise or other unexpected sounds but decreases responsiveness.") + + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + TlabelText { + text: qsTr("minimum note duration") + } + + TspinBox { + id: minDurSpin + + from: settings.instrument !== 3 ? 80 : 160 // longer note if bass + to: 1000 + stepSize: 10 + editable: true + } + + TlabelText { + text: qsTr("[milliseconds]") + } + + } + + } + + Tile { + description: qsTr("Minimum volume of a sound to be pitch-detected") + + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + Text { + text: qsTr("minimum volume") + anchors.verticalCenter: parent.verticalCenter + color: enabled ? activPal.text : disdPal.text + } + + Tslider { + anchors.verticalCenter: parent.verticalCenter + width: Math.min(NOO.factor() * 15, parent.parent.width / 3) + from: 10 + to: 80 + value: volSpin.value + onValueChanged: volSpin.value = value + stepSize: 5 + } + + TspinBox { + id: volSpin + + from: 10 + to: 80 + value: Math.ceil(GLOB.minVolume * 100) + editable: true + } + + TlabelText { + text: "%" + } + + } + + } + + MiddleA440 { + id: freqSpin + + value: GLOB.midAfreq + } + + // advanced settings + Tframe { + width: parent.width * 0.99 + anchors.horizontalCenter: parent.horizontalCenter + + Column { + width: parent.width + spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 + + Switch { + id: advSwitch + + text: qsTr("Advanced") + checked: false + + // There is only one Switch control in Nootka, so far. Style it here + indicator: Rectangle { + implicitWidth: NOO.factor() * 4 + implicitHeight: NOO.factor() + x: advSwitch.leftPadding + y: parent.height / 2 - height / 2 + radius: NOO.factor() + color: advSwitch.checked ? activPal.highlight : activPal.button + border.color: enabled ? activPal.text : disdPal.text //advSwitch.checked ? "#17a81a" : "#cccccc" + + TipRect { + x: advSwitch.checked ? parent.width - width : 0 + anchors.verticalCenter: parent.verticalCenter + width: NOO.factor() * 2 + height: NOO.factor() * 2 + radius: NOO.factor() + rised: !advSwitch.pressed + color: advSwitch.pressed ? activPal.highlight : activPal.button + + Rectangle { + anchors.fill: parent + scale: 0.5 + radius: height / 2 + color: activPal.highlightedText + } + + Behavior on x { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 300 + } + + } + + } + + } + + contentItem: Text { + text: advSwitch.text + opacity: enabled ? 1 : 0.3 + color: enabled ? activPal.text : disdPal.text //advSwitch.down ? "#17a81a" : "#21be2b" + verticalAlignment: Text.AlignVCenter + leftPadding: advSwitch.indicator.width + advSwitch.spacing + } + + } + + Tile { + visible: advSwitch.checked + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() + + TlabelText { + text: qsTr("pitch detection mode") + } + + TcomboBox { + id: methodCombo + + width: NOO.factor() * 20 + model: ["MPM", "autocorrelation", "MPM + modified cepstrum"] + } + + } + + } + + Tile { + visible: advSwitch.checked + description: qsTr("It is rather necessary for mic input but may be switched off for an instrument plugged line-in with less noise.") + + TcheckBox { + id: noiseFilterChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("noise filter") + } + + } + + } - Tframe { // advanced settings - width: parent.width * 0.99 - anchors.horizontalCenter: parent.horizontalCenter - Column { - width: parent.width - spacing: NOO.isAndroid() ? 2 : NOO.factor() / 2 - Switch { - id: advSwitch - text: qsTr("Advanced") - checked: false - - // There is only one Switch control in Nootka, so far. Style it here - indicator: Rectangle { - implicitWidth: NOO.factor() * 4; implicitHeight: NOO.factor() - x: advSwitch.leftPadding; y: parent.height / 2 - height / 2 - radius: NOO.factor() - color: advSwitch.checked ? activPal.highlight : activPal.button - border.color: enabled ? activPal.text : disdPal.text //advSwitch.checked ? "#17a81a" : "#cccccc" - - TipRect { - x: advSwitch.checked ? parent.width - width : 0 - anchors.verticalCenter: parent.verticalCenter - Behavior on x { enabled: GLOB.useAnimations; NumberAnimation { duration: 300 }} - width: NOO.factor() * 2; height: NOO.factor() * 2 - radius: NOO.factor() - rised: !advSwitch.pressed - color: advSwitch.pressed ? activPal.highlight : activPal.button - Rectangle { - anchors.fill: parent; scale: 0.5 - radius: height / 2 - color: activPal.highlightedText } - } - } - contentItem: Text { - text: advSwitch.text - opacity: enabled ? 1.0 : 0.3 - color: enabled ? activPal.text : disdPal.text //advSwitch.down ? "#17a81a" : "#21be2b" - verticalAlignment: Text.AlignVCenter - leftPadding: advSwitch.indicator.width + advSwitch.spacing - } - } - Tile { - visible: advSwitch.checked - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() - TlabelText { text: qsTr("pitch detection mode") } - TcomboBox { - id: methodCombo - width: NOO.factor() * 20 - model: ["MPM", "autocorrelation", "MPM + modified cepstrum"] - } } - } - Tile { - visible: advSwitch.checked - description: qsTr("It is rather necessary for mic input but may be switched off for an instrument plugged line-in with less noise.") + // inCol Column + + } + // listening Tflickable + + } + + // "playing" page + Tflickable { + contentHeight: outCol.height + contentWidth: width + + Column { + id: outCol + + width: parent.width + spacing: NOO.factor() + TcheckBox { - id: noiseFilterChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("noise filter") + id: enableOutChB + + text: qsTr("play sound") + anchors.horizontalCenter: parent.horizontalCenter + checked: true } - } - } - } - } // Column - } // inCol Column - } // listening Tflickable + Column { + enabled: enableOutChB.checked + width: parent.width + spacing: NOO.factor() - Tflickable { // "playing" page - contentHeight: outCol.height - contentWidth: width - Column { - id: outCol - width: parent.width - spacing: NOO.factor() + Tile { + Row { + spacing: NOO.factor() * 2 + anchors.horizontalCenter: parent.horizontalCenter - TcheckBox { - id: enableOutChB - text: qsTr("play sound") - anchors.horizontalCenter: parent.horizontalCenter - checked: true - } + TlabelText { + text: qsTr("output device") + anchors.verticalCenter: parent.verticalCenter + } + + TcomboBox { + id: outDevCombo + + anchors.verticalCenter: parent.verticalCenter + width: NOO.factor() * 20 + model: SOUND.outputDevices() + } + + TcheckBox { + id: jackOutChB + + visible: !NOO.isAndroid() && !NOO.isMac() + anchors.verticalCenter: parent.verticalCenter + text: jackInChB.text + checked: jackInChB.checked + onClicked: jackInChB.checked = jackOutChB.checked + } + + } + + } + + Tile { + description: qsTr("All sounds captured by audio input will be forwarded directly to output device.") + + TcheckBox { + id: forwardInChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("forward input to output") + } + + } + + } - Column { - enabled: enableOutChB.checked - width: parent.width - spacing: NOO.factor() - - Tile { - Row { - spacing: NOO.factor() * 2 - anchors.horizontalCenter: parent.horizontalCenter - TlabelText { text: qsTr("output device"); anchors.verticalCenter: parent.verticalCenter } - TcomboBox { - id: outDevCombo - anchors.verticalCenter: parent.verticalCenter - width: NOO.factor() * 20 - model: SOUND.outputDevices() - } - TcheckBox { - id: jackOutChB - visible: !NOO.isAndroid() && !NOO.isMac() - anchors.verticalCenter: parent.verticalCenter - text: jackInChB.text - checked: jackInChB.checked - onClicked: jackInChB.checked = jackOutChB.checked - } - } - } - Tile { - description: qsTr("All sounds captured by audio input will be forwarded directly to output device.") - TcheckBox { - id: forwardInChB - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("forward input to output") } - } + } - } - } - } - - Component.onCompleted: { - if (inDevCombo.currentIndex === -1) - inDevCombo.model = qsTr("no devices found") - else - inDevCombo.currentIndex = inDevCombo.find(SOUND.currentInDevName()) - minDurSpin.value = Math.ceil(GLOB.minDuration * 1000) - methodCombo.currentIndex = GLOB.detectionMethod - noiseFilterChB.checked = GLOB.useFilter - enableInChB.checked = GLOB.audioInEnabled - jackInChB.checked = GLOB.JACKorASIO - - if (outDevCombo.currentIndex === -1) - outDevCombo.model = qsTr("no devices found") - else - outDevCombo.currentIndex = outDevCombo.find(SOUND.currentOutDevName()) - forwardInChB.checked = GLOB.forwardInput - enableOutChB.checked = GLOB.audioOutEnabled - } - - function save() { - if (enableInChB.checked) { - GLOB.inDevName = inDevCombo.currentText - GLOB.minDuration = minDurSpin.value / 1000.0 - GLOB.minVolume = volSpin.value / 100.0 - GLOB.detectionMethod = methodCombo.currentIndex - GLOB.useFilter = noiseFilterChB.checked - GLOB.midAfreq = freqSpin.value - GLOB.JACKorASIO = jackInChB.checked - } - GLOB.audioInEnabled = enableInChB.checked - if (enableOutChB.checked) { - GLOB.outDevName = outDevCombo.currentText - GLOB.forwardInput = forwardInChB.checked } - GLOB.audioOutEnabled = enableOutChB.checked - SOUND.acceptSettings() - } - - function defaults() { - enableInChB.checked = true - inDevCombo.currentIndex = 0 - minDurSpin.value = 150 - volSpin.value = 40 - freqSpin.value = 440 - methodCombo.currentIndex = 2 - noiseFilterChB.checked = true - freqSpin.value = 440 - jackInChB.checked = false - - enableOutChB.checked = true - outDevCombo.currentIndex = 0 - forwardInChB.checked = false - } - - function help() { NOO.openDocLink("2017/05/17/audio-settings/") } + } diff --git a/src/qml/settings/TbuttonBar.qml b/src/qml/settings/TbuttonBar.qml index 9213c8d4f1299a6bd463c3f4f191f3273931bd3c..ab03f21a328dae6907c4ae727ca09955eb5720ef 100644 --- a/src/qml/settings/TbuttonBar.qml +++ b/src/qml/settings/TbuttonBar.qml @@ -2,41 +2,50 @@ * Copyright (C) 2020-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - ListView { - id: buttBar - orientation: ListView.Horizontal - spacing: NOO.factor() - width: parent.width; height: NOO.factor() * 3 - currentIndex: 0 - leftMargin: NOO.isAndroid() ? 0 : NOO.factor() * 2 - clip: true - - delegate: TabButton { - id: tb - onClicked: buttBar.currentIndex = index - checked: buttBar.currentIndex === index - anchors.verticalCenter: parent.verticalCenter - contentItem: Text { - anchors.centerIn: parent - font.pixelSize: NOO.factor() * 1.25 - text: (index + 1) + ". " + modelData - color: checked ? activPal.highlightedText : activPal.buttonText - style: tb.activeFocus ? Text.Sunken : Text.Normal - styleColor: activPal.text + id: buttBar + + orientation: ListView.Horizontal + spacing: NOO.factor() + width: parent.width + height: NOO.factor() * 3 + currentIndex: 0 + leftMargin: NOO.isAndroid() ? 0 : NOO.factor() * 2 + clip: true + + Rectangle { + z: -1 + width: buttBar.width + height: buttBar.height + color: NOO.isAndroid() ? activPal.base : Qt.darker(activPal.window, 1.1) // the same as DialogButtonBox } - Component.onCompleted: { // only way to get access to TabButton components - background.color = Qt.binding(function() { return checked ? activPal.highlight : activPal.button }) + + delegate: TabButton { + id: tb + + onClicked: buttBar.currentIndex = index + checked: buttBar.currentIndex === index + anchors.verticalCenter: parent.verticalCenter + Component.onCompleted: { + background.color = Qt.binding(function() { + return checked ? activPal.highlight : activPal.button; + }); + } + + contentItem: Text { + anchors.centerIn: parent + font.pixelSize: NOO.factor() * 1.25 + text: (index + 1) + ". " + modelData + color: checked ? activPal.highlightedText : activPal.buttonText + style: tb.activeFocus ? Text.Sunken : Text.Normal + styleColor: activPal.text + } + // only way to get access to TabButton components + } - } - Rectangle { - z: -1 - width: buttBar.width; height: buttBar.height - color: NOO.isAndroid() ? activPal.base : Qt.darker(activPal.window, 1.1) // the same as DialogButtonBox - } } diff --git a/src/qml/settings/TsettingsDialog.qml b/src/qml/settings/TsettingsDialog.qml index 587b963840189a9e95a55eb2af7527633494473c..9828f8b2293b628f4dce2a9cb0c9d1745f513c56 100644 --- a/src/qml/settings/TsettingsDialog.qml +++ b/src/qml/settings/TsettingsDialog.qml @@ -2,55 +2,64 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - Item { - id: settings + id: settings - property int clef: GLOB.clefType - property int instrument: GLOB.instrument.typeINT + property int clef: GLOB.clefType + property int instrument: GLOB.instrument.typeINT - onInstrumentChanged: { - if (pages.buttons.length > 2) - pages.buttons[2].pixmap = NOO.pix("pane/i-0" + instrument) - } + function apply() { + GLOB.clefType = clef; // it can be changed either by score or instrument page + if (NOO.isAndroid()) { + // it may occur only when rotation was enabled and user changed to saxophone - width: parent.width - height: parent.height + if (NOO.instr(instrument).isSax) + GLOB.setDisableRotation(true); + // but has not opened phone settings + } + for (var i = 0; i < pages.pages.length; ++i) { + if (typeof (pages.pages[i]) === 'object') + pages.pages[i].save(); + + } + } - PagesDialog { id: pages } + function reset() { + pages.currentPage.defaults(); + } - Component.onCompleted: { - if (!GLOB.isExam) { - pages.addItem("global", qsTr("Common"), "settings/Global") - pages.addItem("score", qsTr("Score"), "settings/Score") - pages.addItem("i-0" + GLOB.instrument.typeINT, qsTr("Instrument"), "settings/Instrument") - pages.addItem("sound", qsTr("Sound"), "settings/Sound") + function help() { + pages.currentPage.help(); } - pages.addItem("questions", qsTr("Exercises") + "\n& " + qsTr("Exam"), "settings/Exam") - if (NOO.isAndroid() && !GLOB.isExam) - pages.addItem("phoneSett", qsTr("Phone") + "\n& " + qsTr("Tablet"), "settings/Phone") - - dialLoader.standardButtons = DialogButtonBox.Apply | DialogButtonBox.Cancel | DialogButtonBox.RestoreDefaults | DialogButtonBox.Help - dialLoader.title = "Nootka - " + qsTranslate("TsettingsDialog", "application's settings") - } - - function apply() { - GLOB.clefType = clef // it can be changed either by score or instrument page - if (NOO.isAndroid()) { - if (NOO.instr(instrument).isSax) // it may occur only when rotation was enabled and user changed to saxophone - GLOB.setDisableRotation(true) // but has not opened phone settings + + onInstrumentChanged: { + if (pages.buttons.length > 2) + pages.buttons[2].pixmap = NOO.pix("pane/i-0" + instrument); + } - for (var i = 0; i < pages.pages.length; ++i) { - if (typeof(pages.pages[i]) === 'object') - pages.pages[i].save() + width: parent.width + height: parent.height + Component.onCompleted: { + if (!GLOB.isExam) { + pages.addItem("global", qsTr("Common"), "settings/Global"); + pages.addItem("score", qsTr("Score"), "settings/Score"); + pages.addItem("i-0" + GLOB.instrument.typeINT, qsTr("Instrument"), "settings/Instrument"); + pages.addItem("sound", qsTr("Sound"), "settings/Sound"); + } + pages.addItem("questions", qsTr("Exercises") + "\n& " + qsTr("Exam"), "settings/Exam"); + if (NOO.isAndroid() && !GLOB.isExam) + pages.addItem("phoneSett", qsTr("Phone") + "\n& " + qsTr("Tablet"), "settings/Phone"); + + dialLoader.standardButtons = DialogButtonBox.Apply | DialogButtonBox.Cancel | DialogButtonBox.RestoreDefaults | DialogButtonBox.Help; + dialLoader.title = "Nootka - " + qsTranslate("TsettingsDialog", "application's settings"); } - } - function reset() { pages.currentPage.defaults() } + PagesDialog { + id: pages + } - function help() { pages.currentPage.help() } } diff --git a/src/qml/shared/ClefMenu.qml b/src/qml/shared/ClefMenu.qml index 3ff476bb8f2a7c060a95866a68e78d70d3d2ed6e..d2037b440664884535a41a53ae1e10b1a32ad678 100644 --- a/src/qml/shared/ClefMenu.qml +++ b/src/qml/shared/ClefMenu.qml @@ -2,91 +2,127 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 +import Nootka.Music import QtQuick 2.12 import QtQuick.Controls 2.12 - -import Nootka 1.0 import Score 1.0 -import Nootka.Music ListView { - id: clefMenu - width: parent.width; height: parent.height - clip: true - spacing: 1 + id: clefMenu - property int selClef - // private - property var clefNr: [0, 1, 2, 4, 8, 32, 128] + property int selClef + // private + property var clefNr: [0, 1, 2, 4, 8, 32, 128] - signal clicked(var cl) + signal clicked(var cl) + + function checkClef() { + for (var c = 0; c < 7; ++c) { + // so far seven clefs are supported + if (clefNr[c] === selClef) + clefMenu.currentIndex = c; - function checkClef() { - for (var c = 0; c < 7; ++c) { // so far seven clefs are supported - if (clefNr[c] === selClef) - clefMenu.currentIndex = c - } - } - - onSelClefChanged: checkClef() - - onVisibleChanged: { - if (visible) - checkClef() - } - - ScrollBar.vertical: ScrollBar { active: false; visible: active } - - footer: Item { width: parent.width; height: NOO.factor() * 2 } - - model: 7 - delegate: Rectangle { - width: clefMenu.width - height: visible ? NOO.factor() * (index === 6 ? 10 : 7.5) : 0 - visible: index !== 0 || score.meter !== Tmeter.NoMeter - color: index === clefMenu.currentIndex ? activPal.highlight : - (area.containsMouse ? Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 50)) : (index % 2 === 1 ? activPal.alternateBase : activPal.base)) - Row { - height: parent.height - width: parent.width - spacing: NOO.factor() - Item { - width: NOO.factor() * 3.2; height: NOO.factor() - Text { - scale: NOO.factor() * 0.9 - x: scale * 2.5; y: 4.6 * NOO.factor() - font { family: "scorek"; pixelSize: 3 } - text: NOO.clef(clefNr[index]).glyphOnStaff() - color: index === clefMenu.currentIndex ? activPal.highlightedText : activPal.text } - } - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.width - NOO.factor() * 4.8 - spacing: NOO.factor() / 4 - Text { - text: NOO.clef(clefNr[index]).name() - font { bold: true; pixelSize: NOO.factor() * 1.1 } - color: index === clefMenu.currentIndex ? activPal.highlightedText : activPal.text + } + + width: parent.width + height: parent.height + clip: true + spacing: 1 + onSelClefChanged: checkClef() + onVisibleChanged: { + if (visible) + checkClef(); + + } + model: 7 + + ScrollBar.vertical: ScrollBar { + active: false + visible: active + } + + footer: Item { + width: parent.width + height: NOO.factor() * 2 + } + + delegate: Rectangle { + width: clefMenu.width + height: visible ? NOO.factor() * (index === 6 ? 10 : 7.5) : 0 + visible: index !== 0 || score.meter !== Tmeter.NoMeter + color: index === clefMenu.currentIndex ? activPal.highlight : (area.containsMouse ? Qt.tint(activPal.base, NOO.alpha(activPal.highlight, 50)) : (index % 2 === 1 ? activPal.alternateBase : activPal.base)) + + Row { + height: parent.height + width: parent.width + spacing: NOO.factor() + + Item { + width: NOO.factor() * 3.2 + height: NOO.factor() + + Text { + scale: NOO.factor() * 0.9 + x: scale * 2.5 + y: 4.6 * NOO.factor() + text: NOO.clef(clefNr[index]).glyphOnStaff() + color: index === clefMenu.currentIndex ? activPal.highlightedText : activPal.text + + font { + family: "scorek" + pixelSize: 3 + } + + } + + } + + Column { + anchors.verticalCenter: parent.verticalCenter + width: parent.width - NOO.factor() * 4.8 + spacing: NOO.factor() / 4 + + Text { + text: NOO.clef(clefNr[index]).name() + color: index === clefMenu.currentIndex ? activPal.highlightedText : activPal.text + + font { + bold: true + pixelSize: NOO.factor() * 1.1 + } + + } + + Text { + text: NOO.clef(clefNr[index]).desc() + width: parent.width + wrapMode: Text.WordWrap + color: index === clefMenu.currentIndex ? activPal.highlightedText : activPal.text + + font { + pixelSize: NOO.factor() * 0.8 + } + + } + + } + } - Text { - text: NOO.clef(clefNr[index]).desc() - font { pixelSize: NOO.factor() * 0.8 } - width: parent.width - wrapMode: Text.WordWrap - color: index === clefMenu.currentIndex ? activPal.highlightedText : activPal.text + + MouseArea { + id: area + + anchors.fill: parent + hoverEnabled: true + onClicked: { + selClef = clefNr[index]; + clefMenu.currentIndex = index; + clefMenu.clicked(clefNr[index]); + } } - } - } - MouseArea { - anchors.fill: parent - id: area - hoverEnabled: true - onClicked: { - selClef = clefNr[index] - clefMenu.currentIndex = index - clefMenu.clicked(clefNr[index]) - } + } - } + } diff --git a/src/qml/shared/DivideMelody.qml b/src/qml/shared/DivideMelody.qml index 2a7a30601da58b96da9cbe5414f0622bec6a2e04..b103a70ef563a0445a3e7e844bd8b20183f2d502 100644 --- a/src/qml/shared/DivideMelody.qml +++ b/src/qml/shared/DivideMelody.qml @@ -2,26 +2,34 @@ * Copyright (C) 2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - Column { - property alias divisionBy: splitSpin.value + property alias divisionBy: splitSpin.value - spacing: NOO.factor() - Row { - id: splitRow - anchors.horizontalCenter: parent.horizontalCenter spacing: NOO.factor() - Text { - anchors.verticalCenter: parent.verticalCenter - color: activPal.text; text: qsTr("Divide by selected bars number") - } - TspinBox { - id: splitSpin - from: 0; to: 64 + + Row { + id: splitRow + + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() + + Text { + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + text: qsTr("Divide by selected bars number") + } + + TspinBox { + id: splitSpin + + from: 0 + to: 64 + } + } - } + } diff --git a/src/qml/shared/GlowRect.qml b/src/qml/shared/GlowRect.qml index f1f7a03068b856421f381d7eb4c97fc114319494..dfcf26e4309a7dcada13698674e4df1c7af961e6 100644 --- a/src/qml/shared/GlowRect.qml +++ b/src/qml/shared/GlowRect.qml @@ -2,31 +2,34 @@ * 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 Qt5Compat.GraphicalEffects - import Nootka 1.0 +import Qt5Compat.GraphicalEffects +import QtQuick 2.12 Rectangle { - property bool rised: true - property alias shadowRadius: glow.glowRadius - property alias shadowColor: glow.color - property alias horizontalOffset: glow.x - property alias verticalOffset: glow.y - property alias spread: glow.spread - property alias cornerRadius: glow.cornerRadius + property bool rised: true + property alias shadowRadius: glow.glowRadius + property alias shadowColor: glow.color + property alias horizontalOffset: glow.x + property alias verticalOffset: glow.y + property alias spread: glow.spread + property alias cornerRadius: glow.cornerRadius + + color: activPal.base + radius: NOO.factor() / 3 + + RectangularGlow { + id: glow - color: activPal.base - radius: NOO.factor() / 3 + width: parent.width + height: parent.height + x: rised ? NOO.factor() / 6 : 0 + y: rised ? NOO.factor() / 6 : 0 + z: -1 + glowRadius: NOO.factor() / 3 + spread: 0 + color: activPal.shadow + cornerRadius: parent.radius + glowRadius * spread + } - RectangularGlow { - id: glow - width: parent.width; height: parent.height - x: rised ? NOO.factor() / 6 : 0; y: rised ? NOO.factor() / 6 : 0 - z: -1 - glowRadius: NOO.factor() / 3 - spread: 0 - color: activPal.shadow - cornerRadius: parent.radius + glowRadius * spread - } } diff --git a/src/qml/shared/HeadButton.qml b/src/qml/shared/HeadButton.qml index 39b9ae673a95969f56d6365b4da01142582e8220..d67b87ab1fc9c3b168b8d877ed751be6a4ae6701 100644 --- a/src/qml/shared/HeadButton.qml +++ b/src/qml/shared/HeadButton.qml @@ -2,78 +2,120 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 +ToolButton { + id: root + property alias pixmap: pix.source + property alias name: butText.text + property real factor: nootkaWindow.width / 240 + property alias fontSize: butText.font.pixelSize + property alias textColor: butText.color + property Taction taction + property bool hiHover: true -ToolButton { - id: root + hoverEnabled: true + width: Math.max(pix.width, butText.width) + (NOO.isAndroid() ? 4 : factor * 2) + height: butText.height + pix.height + NOO.factor() / 4 + onHoveredChanged: { + if (GLOB.showHints && taction && taction.tip !== "") { + if (hovered) + NOO.setStatusTip(taction.tip, taction.tipPos); + else + NOO.setStatusTip("", taction.tipPos); + } + } + onClicked: { + if (taction) + taction.trigger(); + + focus = false; + } + + Text { + id: butText + + text: taction ? taction.text : "" + font.pixelSize: Math.min(factor * 2.5, NOO.factor()) + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + horizontalAlignment: Text.AlignHCenter + color: activPal.text + } + + Image { + id: pix + + mipmap: true + source: taction ? taction.icon : "" + y: NOO.factor() / 4 + (GLOB.useAnimations && !pressed && hiHover && hovered ? (root.height - height - NOO.factor() / 4) / 2 : 0) + height: factor * 8 + width: height * (sourceSize.width / sourceSize.height) + anchors.horizontalCenter: butText.horizontalCenter + transformOrigin: Image.Center + scale: pressed ? 0.9 : (GLOB.useAnimations && hiHover && hovered ? root.height / height : 1) + + Behavior on scale { + enabled: GLOB.useAnimations - hoverEnabled: true + NumberAnimation { + duration: 150 + } - width: Math.max(pix.width, butText.width) + (NOO.isAndroid() ? 4 : factor * 2) - height: butText.height + pix.height + NOO.factor() / 4.0 + } - property alias pixmap: pix.source - property alias name: butText.text - property real factor: nootkaWindow.width / 240 - property alias fontSize: butText.font.pixelSize - property alias textColor: butText.color - property Taction taction - property bool hiHover: true + Behavior on y { + enabled: GLOB.useAnimations - background: Item {} + NumberAnimation { + duration: 150 + } - onHoveredChanged: { - if (GLOB.showHints && taction && taction.tip !== "") { - if (hovered) - NOO.setStatusTip(taction.tip, taction.tipPos) - else - NOO.setStatusTip("", taction.tipPos) + } + + } + + Connections { + target: taction + onShakeButton: shakeAnim.running = true } - } - - onClicked: { - if (taction) - taction.trigger() - focus = false - } - - Text { - id: butText - text: taction ? taction.text : "" - font.pixelSize: Math.min(factor * 2.5, NOO.factor()) - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - horizontalAlignment: Text.AlignHCenter - color: activPal.text - } - - Image { - id: pix - mipmap: true - source: taction ? taction.icon : "" - y: NOO.factor() / 4.0 + (GLOB.useAnimations && !pressed && hiHover && hovered ? (root.height - height - NOO.factor() / 4.0) / 2 : 0) - height: factor * 8; width: height * (sourceSize.width / sourceSize.height) - anchors.horizontalCenter: butText.horizontalCenter - transformOrigin: Image.Center; scale: pressed ? 0.9 : (GLOB.useAnimations && hiHover && hovered ? root.height / height : 1.0) - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - Behavior on y { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - } - - Connections { - target: taction - onShakeButton: shakeAnim.running = true - } - - SequentialAnimation { - id: shakeAnim - running: false - loops: 3 - NumberAnimation { target: root; property: "rotation"; from: 0; to: -30; duration: 50 } - NumberAnimation { target: root; property: "rotation"; from: -30; to: 30; duration: 100 } - NumberAnimation { target: root; property: "rotation"; from: 30; to: 0; duration: 50 } - } + + SequentialAnimation { + id: shakeAnim + + running: false + loops: 3 + + NumberAnimation { + target: root + property: "rotation" + from: 0 + to: -30 + duration: 50 + } + + NumberAnimation { + target: root + property: "rotation" + from: -30 + to: 30 + duration: 100 + } + + NumberAnimation { + target: root + property: "rotation" + from: 30 + to: 0 + duration: 50 + } + + } + + background: Item { + } + } diff --git a/src/qml/shared/InstrumentSelector.qml b/src/qml/shared/InstrumentSelector.qml index d65e81e46a7d8c17ad4cb811c5b62b57348a9def..7a0d9a3dc7f905c33b5b9c717fc1f0deb7653616 100644 --- a/src/qml/shared/InstrumentSelector.qml +++ b/src/qml/shared/InstrumentSelector.qml @@ -2,74 +2,109 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - Tumbler { - id: instrTumb - - property alias instrument: instrTumb.currentIndex - - width: parent.width - height: NOO.factor() * (NOO.isAndroid() ? 7 : 10) - visibleItemCount: Math.min(((width / (height * 0.7)) / 2) * 2 - 1, 7) - model: 9 - delegate: Component { - Item { - opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) - scale: (1.7 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2)) * (textMa.pressed || glyphMa.pressed ? 0.8 : 1.0) - Text { - id: instrGlyph - property color tc: NOO.randomColor() - font {family: "nootka"; pixelSize: instrTumb.height * 0.3 } - text: NOO.instr(modelData).glyph - anchors.horizontalCenter: parent.horizontalCenter - color: instrTumb.currentIndex === modelData ? activPal.highlightedText : tc - MouseArea { - id: glyphMa - anchors.fill: parent - onClicked: instrTumb.currentIndex = modelData - } - } - Text { - anchors { horizontalCenter: parent.horizontalCenter; top: instrGlyph.bottom } - width: instrTumb.height * 0.8 - text: NOO.instr(modelData).name.replace(" ", "\n") - horizontalAlignment: Text.AlignHCenter - color: activPal.text - font { bold: instrTumb.currentIndex === modelData; pixelSize: instrTumb.height * 0.08 } - MouseArea { - id: textMa - anchors.fill: parent - onClicked: instrTumb.currentIndex = modelData + id: instrTumb + + property alias instrument: instrTumb.currentIndex + + width: parent.width + height: NOO.factor() * (NOO.isAndroid() ? 7 : 10) + visibleItemCount: Math.min(((width / (height * 0.7)) / 2) * 2 - 1, 7) + model: 9 + + Rectangle { + z: -1 + width: instrTumb.height * 0.9 + height: parent.height * 0.5 + x: parent.width / 2 - width / 2 + y: 2 + color: activPal.highlight + radius: width / 12 + } + + delegate: Component { + Item { + opacity: 1 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) + scale: (1.7 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2)) * (textMa.pressed || glyphMa.pressed ? 0.8 : 1) + + Text { + id: instrGlyph + + property color tc: NOO.randomColor() + + text: NOO.instr(modelData).glyph + anchors.horizontalCenter: parent.horizontalCenter + color: instrTumb.currentIndex === modelData ? activPal.highlightedText : tc + + font { + family: "nootka" + pixelSize: instrTumb.height * 0.3 + } + + MouseArea { + id: glyphMa + + anchors.fill: parent + onClicked: instrTumb.currentIndex = modelData + } + + } + + Text { + width: instrTumb.height * 0.8 + text: NOO.instr(modelData).name.replace(" ", "\n") + horizontalAlignment: Text.AlignHCenter + color: activPal.text + + anchors { + horizontalCenter: parent.horizontalCenter + top: instrGlyph.bottom + } + + font { + bold: instrTumb.currentIndex === modelData + pixelSize: instrTumb.height * 0.08 + } + + MouseArea { + id: textMa + + anchors.fill: parent + onClicked: instrTumb.currentIndex = modelData + } + + } + } - } + } - } - contentItem: PathView { - id: pathView - model: instrTumb.model - delegate: instrTumb.delegate - clip: true - pathItemCount: instrTumb.visibleItemCount + 1 - preferredHighlightBegin: 0.5 - preferredHighlightEnd: 0.5 - dragMargin: width / 2 - path: Path { - startX: 0 - startY: instrTumb.height * 0.14 - PathLine { - x: pathView.width - y: instrTumb.height * 0.14 - } + + contentItem: PathView { + id: pathView + + model: instrTumb.model + delegate: instrTumb.delegate + clip: true + pathItemCount: instrTumb.visibleItemCount + 1 + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + dragMargin: width / 2 + + path: Path { + startX: 0 + startY: instrTumb.height * 0.14 + + PathLine { + x: pathView.width + y: instrTumb.height * 0.14 + } + + } + } - } - Rectangle { - z: -1; width: instrTumb.height * 0.9; height: parent.height * 0.5 - x: parent.width / 2 - width / 2; y: 2 - color: activPal.highlight - radius: width / 12 - } + } diff --git a/src/qml/shared/LinkText.qml b/src/qml/shared/LinkText.qml index b40b2001d30af66ee0459b979730dfae4fffb69b..62aa68e8c8e72392f8978666053418de7ae0d517 100644 --- a/src/qml/shared/LinkText.qml +++ b/src/qml/shared/LinkText.qml @@ -4,13 +4,14 @@ import QtQuick 2.12 - Text { - color: activPal.text - onLinkActivated: Qt.openUrlExternally(link) - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - } + color: activPal.text + onLinkActivated: Qt.openUrlExternally(link) + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } + } diff --git a/src/qml/shared/MenuButton.qml b/src/qml/shared/MenuButton.qml index 7c51de49796cd1c0db6b5f0f3428c5f2bae197da..e478c9c3cc329d9bf45a9697ef72ec3419d16df1 100644 --- a/src/qml/shared/MenuButton.qml +++ b/src/qml/shared/MenuButton.qml @@ -2,108 +2,140 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 +Rectangle { + id: menuButton + property Taction action + property alias text: butText.text + property alias iconHeight: icon.height + property alias containsMouse: ma.containsMouse + property alias containsPress: ma.containsPress + property alias textColor: butText.color + // private + property var shortText: null + + signal clicked() + + function buttonClicked() { + menuButton.clicked(); + if (action) + action.trigger(); + + } + + width: parent.width - NOO.factor() + implicitHeight: NOO.factor() * 2.8 + anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined + color: ma.containsPress ? activPal.highlight : (ma.containsMouse ? NOO.alpha(activPal.highlight, 50) : "transparent") + enabled: !action || action.enabled + scale: GLOB.useAnimations && ma.pressed ? 0.9 : 1 + onActionChanged: { + if (action && action.checkable) + radioComp.createObject(menuButton); + + } + Component.onCompleted: { + // shortcut is known only now + if (!NOO.isAndroid() && action && action.shortcut) + shortText = shortComp.createObject(menuButton); + + } + + Image { + id: icon + + source: action && !action.checkable ? action.icon : "" + x: NOO.factor() / 2 + height: NOO.factor() * 2.2 + width: height * (sourceSize.width / sourceSize.height) + anchors.verticalCenter: parent.verticalCenter + scale: GLOB.useAnimations && !ma.pressed && ma.containsMouse ? 1.2 : 1 + visible: menuButton.enabled + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } -Rectangle { - id: menuButton - - property Taction action - property alias text: butText.text - property alias iconHeight: icon.height - property alias containsMouse: ma.containsMouse - property alias containsPress: ma.containsPress - property alias textColor: butText.color - - width: parent.width - NOO.factor() - implicitHeight: NOO.factor() * 2.8 - anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined - color: ma.containsPress ? activPal.highlight : (ma.containsMouse ? NOO.alpha(activPal.highlight, 50) : "transparent") - enabled: !action || action.enabled - - signal clicked() - - // private - property var shortText: null - - scale: GLOB.useAnimations && ma.pressed ? 0.9 : 1.0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - - onActionChanged: { - if (action && action.checkable) - radioComp.createObject(menuButton) - } - - Image { - id: icon - source: action && !action.checkable ? action.icon : "" - x: NOO.factor() / 2 - height: NOO.factor() * 2.2; width: height * (sourceSize.width / sourceSize.height) - anchors.verticalCenter: parent.verticalCenter - scale: GLOB.useAnimations && !ma.pressed && ma.containsMouse ? 1.2 : 1.0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - visible: menuButton.enabled - } - Text { - id: butText - x: NOO.factor() * (action && (action.icon !== "" || action.checkable) ? 3.7 : 0.8) - text: action ? action.text : "" - font { bold: true; pixelSize: NOO.factor() } - color: enabled ? activPal.text : disdPal.text - width: parent.width - x - NOO.factor() - (shortText ? shortText.width : 0) - height: parent.height - verticalAlignment: Text.AlignVCenter - fontSizeMode: Text.HorizontalFit; minimumPixelSize: NOO.factor() / 2; minimumPointSize: minimumPixelSize - elide: Text.ElideRight - } - - Component { - id: radioComp - TcheckBox { - anchors.verticalCenter: parent.verticalCenter - checked: menuButton.action.checked - onClicked: buttonClicked() - x: (NOO.factor() * 3.5 - width) / 2 } - } - Component { - id: shortComp Text { - anchors.verticalCenter: parent.verticalCenter - text: action.key() - font.pixelSize: NOO.factor() * 0.8 - x: menuButton.width - width - NOO.factor() / 2 - color: enabled ? activPal.text : disdPal.text + id: butText + + x: NOO.factor() * (action && (action.icon !== "" || action.checkable) ? 3.7 : 0.8) + text: action ? action.text : "" + color: enabled ? activPal.text : disdPal.text + width: parent.width - x - NOO.factor() - (shortText ? shortText.width : 0) + height: parent.height + verticalAlignment: Text.AlignVCenter + fontSizeMode: Text.HorizontalFit + minimumPixelSize: NOO.factor() / 2 + minimumPointSize: minimumPixelSize + elide: Text.ElideRight + + font { + bold: true + pixelSize: NOO.factor() + } + + } + + Component { + id: radioComp + + TcheckBox { + anchors.verticalCenter: parent.verticalCenter + checked: menuButton.action.checked + onClicked: buttonClicked() + x: (NOO.factor() * 3.5 - width) / 2 + } + + } + + Component { + id: shortComp + + Text { + anchors.verticalCenter: parent.verticalCenter + text: action.key() + font.pixelSize: NOO.factor() * 0.8 + x: menuButton.width - width - NOO.factor() / 2 + color: enabled ? activPal.text : disdPal.text + } + + } + + MouseArea { + id: ma + + anchors.fill: parent + hoverEnabled: true + onClicked: buttonClicked() + onHoveredChanged: { + if (action) { + if (GLOB.showHints && action.tip !== "" && ma.containsMouse) + NOO.setStatusTip(action.tip, action.tipPos); + else + NOO.setStatusTip("", action.tipPos); + } + } } - } - - Component.onCompleted: { // shortcut is known only now - if (!NOO.isAndroid() && action && action.shortcut) - shortText = shortComp.createObject(menuButton) - } - - MouseArea { - id: ma - anchors.fill: parent - hoverEnabled: true - onClicked: buttonClicked() - onHoveredChanged: { - if (action) { - if (GLOB.showHints && action.tip !== "" && ma.containsMouse) - NOO.setStatusTip(action.tip, action.tipPos) - else - NOO.setStatusTip("", action.tipPos) - } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + } - } - function buttonClicked() { - menuButton.clicked() - if (action) - action.trigger() - } } diff --git a/src/qml/shared/NameStyleSelector.qml b/src/qml/shared/NameStyleSelector.qml index 89fda438c7f58beab73c3e9d7415fe6da45aab08..512bb167b33c2b279b028cf352ff81f1fb50413e 100644 --- a/src/qml/shared/NameStyleSelector.qml +++ b/src/qml/shared/NameStyleSelector.qml @@ -2,92 +2,113 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 +Item { + id: root + property bool seventhIsB: true + property int style: -1 -Item { - id: root - - property bool seventhIsB: true - property int style: -1 - - width: childrenRect.width - height: childrenRect.height - antialiasing: true - - ButtonGroup { - id: styleGr - buttons: styleColumn.children - onClicked: style = button.style - } - - onStyleChanged: { - for (var b = 0; b < 6; ++b) { - if (styleGr.buttons[b].style == style) { - styleGr.buttons[b].checked = true; - break; - } + width: childrenRect.width + height: childrenRect.height + antialiasing: true + onStyleChanged: { + for (var b = 0; b < 6; ++b) { + if (styleGr.buttons[b].style == style) { + styleGr.buttons[b].checked = true; + break; + } + } } - } - - onSeventhIsBChanged: { - if (seventhIsB) { - if (styleGr.buttons[0].checked) - root.style = Nootka.English_Bb - else if (styleGr.buttons[1].checked) - root.style = Nootka.Nederl_Bis - } else { - if (styleGr.buttons[3].checked) - root.style = Nootka.Norsk_Hb - else if (styleGr.buttons[4].checked) - root.style = Nootka.Deutsch_His + onSeventhIsBChanged: { + if (seventhIsB) { + if (styleGr.buttons[0].checked) + root.style = Nootka.English_Bb; + else if (styleGr.buttons[1].checked) + root.style = Nootka.Nederl_Bis; + } else { + if (styleGr.buttons[3].checked) + root.style = Nootka.Norsk_Hb; + else if (styleGr.buttons[4].checked) + root.style = Nootka.Deutsch_His; + } } - } - Column { - Text { - text: qsTr("Naming style") - anchors.horizontalCenter: parent.horizontalCenter - color: enabled ? activPal.text : disdPal.text + ButtonGroup { + id: styleGr + + buttons: styleColumn.children + onClicked: style = button.style } - Tframe { - width: NOO.factor() * 25 - Column { - id: styleColumn - spacing: NOO.factor() / 2 - TradioButton { // 0 - default property int style: Nootka.Norsk_Hb - text: qsTr("Scandinavian") + " (C, C#, Db ... Hb, H)" - visible: !seventhIsB - } - TradioButton { // 1 - default property int style: Nootka.Deutsch_His - text: qsTr("German") + " (C, Cis, Des ... B, H)" - visible: !seventhIsB + Column { + Text { + text: qsTr("Naming style") + anchors.horizontalCenter: parent.horizontalCenter + color: enabled ? activPal.text : disdPal.text } - TradioButton { // 2 - default property int style: Nootka.Italiano_Si - text: qsTr("Italian") + " (Do, Do#, Reb ... Sib, Si)" - } - TradioButton { // 3 - default property int style: Nootka.English_Bb - text: qsTr("English") + " (C, C#, Db ... Bb, B)" - visible: seventhIsB - } - TradioButton { // 4 - default property int style: Nootka.Nederl_Bis - text: qsTr("Dutch") + " (C, Cis, Des ... Bes, B)" - visible: seventhIsB - } - TradioButton { // 5 - default property int style: Nootka.Russian_Ci - text: qsTr("Russian") + " (До, До# Реb ... Сиb, Си)" + + Tframe { + width: NOO.factor() * 25 + + Column { + id: styleColumn + + spacing: NOO.factor() / 2 + + // 0 + TradioButton { + default property int style: Nootka.Norsk_Hb + + text: qsTr("Scandinavian") + " (C, C#, Db ... Hb, H)" + visible: !seventhIsB + } + + // 1 + TradioButton { + default property int style: Nootka.Deutsch_His + + text: qsTr("German") + " (C, Cis, Des ... B, H)" + visible: !seventhIsB + } + + // 2 + TradioButton { + default property int style: Nootka.Italiano_Si + + text: qsTr("Italian") + " (Do, Do#, Reb ... Sib, Si)" + } + + // 3 + TradioButton { + default property int style: Nootka.English_Bb + + text: qsTr("English") + " (C, C#, Db ... Bb, B)" + visible: seventhIsB + } + + // 4 + TradioButton { + default property int style: Nootka.Nederl_Bis + + text: qsTr("Dutch") + " (C, Cis, Des ... Bes, B)" + visible: seventhIsB + } + + // 5 + TradioButton { + default property int style: Nootka.Russian_Ci + + text: qsTr("Russian") + " (До, До# Реb ... Сиb, Си)" + } + + } + } - } + } - } + } diff --git a/src/qml/shared/PagesDialog.qml b/src/qml/shared/PagesDialog.qml index 8a58f81a2730c5edae89f6c09d4b6e2444fa162f..faa2928bcef657df368a05e8d37f54c6c5cb5067 100755 --- a/src/qml/shared/PagesDialog.qml +++ b/src/qml/shared/PagesDialog.qml @@ -2,130 +2,193 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - /** * Implements a dialog with navigation list on the left * Model has following fields: * 'icon', 'text' and 'page' - with path to QML file */ Grid { - id: pagesGrid - - property bool topToBott: parent.height > parent.width - property alias stack: stack - property alias model: navList.model - property var pages: [] - property alias currentPage: stack.currentItem - property var buttons: [] - - width: parent.width; height: parent.height - - function addItem(icon, text, page) { - pages.push("qrc:/" + page + "Page.qml") - model.append({ "iconName": "pane/" + icon, "buttonText": text }) - } - - columns: topToBott ? 1 : 2 - - spacing: 1 - - // private - property real maxWidth: 0 - property real maxHeight: 0 - - // navigation list on the left or top - Rectangle { // background - color: NOO.isAndroid() ? "#000000" : "#ffffff" - height: topToBott ? maxHeight + NOO.factor() / 2 : pagesGrid.height - width: topToBott ? pagesGrid.width : maxWidth - z: -1 - - Flickable { - id: paneFlick - clip: true - anchors.fill: parent - topMargin: NOO.factor() / 2 - contentWidth: paneGrid.width; contentHeight: paneGrid.height - - Rectangle { // highlight - width: navList.prevButt.width; height: navList.prevButt.height + NOO.factor() / 4 - color: activPal.highlight - y: navList.prevButt.y - NOO.factor() / 8; x: navList.prevButt.x - Behavior on y { enabled: GLOB.useAnimations; SpringAnimation { spring: 2; damping: 0.1 }} - Behavior on x { enabled: GLOB.useAnimations; SpringAnimation { spring: 2; damping: 0.1 }} - } - - Grid { - id: paneGrid - spacing: NOO.factor() / 4 - columns: topToBott ? model.count : 1 - - Repeater { - id: navList - property PaneButton prevButt: null - - model: ListModel { id: pageModel } - - delegate: PaneButton { - id: delegateButt - name: buttonText - pixmap: NOO.pix(iconName) - onClicked: selectPage(index) - - Component.onCompleted: { - maxWidth = Math.max(maxWidth, width) - maxHeight = Math.max(maxHeight, height) - buttons.push(delegateButt) - for (var i = 0; i < buttons.length; ++i) // keep buttons width the same - buttons[i].width = maxWidth - if (index === 0) { - navList.prevButt = delegateButt - pages[0] = stack.push(Qt.createComponent(pages[0]).createObject(stack)) - } + id: pagesGrid + + property bool topToBott: parent.height > parent.width + property alias stack: stack + property alias model: navList.model + property var pages: [] + property alias currentPage: stack.currentItem + property var buttons: [] + // private + property real maxWidth: 0 + property real maxHeight: 0 + + function addItem(icon, text, page) { + pages.push("qrc:/" + page + "Page.qml"); + model.append({ + "iconName": "pane/" + icon, + "buttonText": text + }); + } + + function selectPage(pageId) { + if (navList.prevButt !== buttons[pageId]) { + if (typeof (pages[pageId]) === "string") + pages[pageId] = Qt.createComponent(pages[pageId]).createObject(stack); + + pages[pageId] = stack.replace(pages[pageId]); + paneFlick.ensureVisible(buttons[pageId].y, buttons[pageId].height, buttons[pageId].x, buttons[pageId].width); + navList.prevButt = buttons[pageId]; + } + } + + width: parent.width + height: parent.height + columns: topToBott ? 1 : 2 + spacing: 1 + + // navigation list on the left or top + Rectangle { + // background + color: NOO.isAndroid() ? "#000000" : "#ffffff" + height: topToBott ? maxHeight + NOO.factor() / 2 : pagesGrid.height + width: topToBott ? pagesGrid.width : maxWidth + z: -1 + + Flickable { + id: paneFlick + + function ensureVisible(yy, hh, xx, ww) { + if (contentY > yy) + contentY = yy; + else if (contentY + height <= yy + hh) + contentY = yy + hh - height; + if (contentX > xx) + contentX = xx; + else if (contentX + width <= xx + ww) + contentX = xx + ww - width; + } + + clip: true + anchors.fill: parent + topMargin: NOO.factor() / 2 + contentWidth: paneGrid.width + contentHeight: paneGrid.height + + // highlight + Rectangle { + width: navList.prevButt.width + height: navList.prevButt.height + NOO.factor() / 4 + color: activPal.highlight + y: navList.prevButt.y - NOO.factor() / 8 + x: navList.prevButt.x + + Behavior on y { + enabled: GLOB.useAnimations + + SpringAnimation { + spring: 2 + damping: 0.1 + } + + } + + Behavior on x { + enabled: GLOB.useAnimations + + SpringAnimation { + spring: 2 + damping: 0.1 + } + + } + + } + + Grid { + id: paneGrid + + spacing: NOO.factor() / 4 + columns: topToBott ? model.count : 1 + + Repeater { + id: navList + + property PaneButton prevButt: null + + model: ListModel { + id: pageModel + } + + delegate: PaneButton { + id: delegateButt + + name: buttonText + pixmap: NOO.pix(iconName) + onClicked: selectPage(index) + Component.onCompleted: { + // keep buttons width the same + + maxWidth = Math.max(maxWidth, width); + maxHeight = Math.max(maxHeight, height); + buttons.push(delegateButt); + for (var i = 0; i < buttons.length; ++i) buttons[i].width = maxWidth + if (index === 0) { + navList.prevButt = delegateButt; + pages[0] = stack.push(Qt.createComponent(pages[0]).createObject(stack)); + } + } + } + + } + + } + + ScrollBar.vertical: ScrollBar { + visible: !topToBott + active: false + } + + ScrollBar.horizontal: ScrollBar { + visible: topToBott + active: false } - } } - } - - ScrollBar.vertical: ScrollBar { visible: !topToBott; active: false } - ScrollBar.horizontal: ScrollBar { visible: topToBott; active: false } - - function ensureVisible(yy, hh, xx, ww) { - if (contentY > yy) - contentY = yy - else if (contentY + height <= yy + hh) - contentY = yy + hh - height - if (contentX > xx) - contentX = xx - else if (contentX + width <= xx + ww) - contentX = xx + ww - width - } + } - } - - function selectPage(pageId) { - if (navList.prevButt !== buttons[pageId]) { - if (typeof(pages[pageId]) === "string") - pages[pageId] = Qt.createComponent(pages[pageId]).createObject(stack) - pages[pageId] = stack.replace(pages[pageId]) - paneFlick.ensureVisible(buttons[pageId].y, buttons[pageId].height, buttons[pageId].x, buttons[pageId].width) - navList.prevButt = buttons[pageId] + + // pages container on the right or bottom + StackView { + id: stack + + clip: true + width: pagesGrid.width - (topToBott ? 0 : maxWidth) - pagesGrid.spacing + height: pagesGrid.height - (topToBott ? maxHeight + NOO.factor() / 2 : 0) + + replaceEnter: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "x" + from: width + to: 0 + } + + } + + replaceExit: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "x" + from: 0 + to: -width + } + + } + } - } - - // pages container on the right or bottom - StackView { - id: stack - clip: true - width: pagesGrid.width - (topToBott ? 0 : maxWidth) - pagesGrid.spacing - height: pagesGrid.height - (topToBott ? maxHeight + NOO.factor() / 2 : 0) - replaceEnter: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "x"; from: width; to: 0 }} - replaceExit: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "x"; from: 0; to: -width }} - } -} +} diff --git a/src/qml/shared/PaneButton.qml b/src/qml/shared/PaneButton.qml index d7b74dd0c0519a506e43eab120a271e2a3f25b12..3ff3ecacd8f383a325846f7b8c974c71b7ba0810 100644 --- a/src/qml/shared/PaneButton.qml +++ b/src/qml/shared/PaneButton.qml @@ -2,60 +2,87 @@ * Copyright (C) 2019-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 +import QtGraphicalEffects 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import QtGraphicalEffects 1.0 -import Nootka 1.0 +AbstractButton { + id: root + property alias pixmap: pix.source + property alias name: butText.text + property real factor: NOO.factor() * (NOO.isAndroid() ? 0.45 : 0.7) -AbstractButton { - id: root - - hoverEnabled: !NOO.isAndroid() - - width: Math.max(pix.width, butText.width) + factor * 2 - - property alias pixmap: pix.source - property alias name: butText.text - property real factor: NOO.factor() * (NOO.isAndroid() ? 0.45 : 0.7) - - contentItem: Column { - width: parent.width - spacing: factor / 2 - GlowRect { - id: bg - anchors.horizontalCenter: parent.horizontalCenter - z: 1 - radius: NOO.factor() / 2 - color: enabled ? (root.checked ? activPal.highlight : "#ffffff") : "#cbcbcb" - shadowColor: "#101010" - height: factor * 8; width: height - Image { - id: pix - mipmap: true - height: parent.height * 0.9; width: height * (sourceSize.width / sourceSize.height) - anchors.centerIn: parent - visible: enabled - } - Colorize { - source: pix - saturation: 0; hue: 0; lightness: 0 - anchors.fill: pix - visible: !enabled - } - transformOrigin: Image.Center; scale: !enabled || pressed ? 0.8 : (GLOB.useAnimations && hovered ? 1.2 : 1.0) - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - Behavior on color { enabled: GLOB.useAnimations; ColorAnimation { duration: 150 }} - } + hoverEnabled: !NOO.isAndroid() + width: Math.max(pix.width, butText.width) + factor * 2 + + contentItem: Column { + width: parent.width + spacing: factor / 2 + + GlowRect { + id: bg + + anchors.horizontalCenter: parent.horizontalCenter + z: 1 + radius: NOO.factor() / 2 + color: enabled ? (root.checked ? activPal.highlight : "#ffffff") : "#cbcbcb" + shadowColor: "#101010" + height: factor * 8 + width: height + transformOrigin: Image.Center + scale: !enabled || pressed ? 0.8 : (GLOB.useAnimations && hovered ? 1.2 : 1) + + Image { + id: pix + + mipmap: true + height: parent.height * 0.9 + width: height * (sourceSize.width / sourceSize.height) + anchors.centerIn: parent + visible: enabled + } + + Colorize { + source: pix + saturation: 0 + hue: 0 + lightness: 0 + anchors.fill: pix + visible: !enabled + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + Behavior on color { + enabled: GLOB.useAnimations + + ColorAnimation { + duration: 150 + } + + } + + } + + Text { + id: butText + + z: 0 + color: enabled ? (NOO.isAndroid() ? "#ffffff" : "#000000") : "#999999" + font.pixelSize: NOO.factor() * (NOO.isAndroid() ? 0.8 : 1) + horizontalAlignment: Text.AlignHCenter + anchors.horizontalCenter: parent.horizontalCenter + } - Text { - id: butText - z: 0 - color: enabled ? (NOO.isAndroid() ? "#ffffff" : "#000000") : "#999999" - font.pixelSize: NOO.factor() * (NOO.isAndroid() ? 0.8 : 1) - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter } - } + } diff --git a/src/qml/shared/RectButton.qml b/src/qml/shared/RectButton.qml index 0d18433288c325b8954639a5da3525906b987898..1fba2c5f18fd78b0ec2f79a7c598555c4a474bf8 100644 --- a/src/qml/shared/RectButton.qml +++ b/src/qml/shared/RectButton.qml @@ -2,49 +2,67 @@ * Copyright (C) 2019-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - AbstractButton { - id: rectButt - - property string statusTip: "" - property int statusPos: Item.TopLeft - property alias textColor: tx.color - - /** Properties to handle Scorek glyphs which are out of rectangle */ - property alias forcedHeight: bg.height - property alias yOffset: tx.topPadding - - height: parent.height - hoverEnabled: true - - contentItem: Text { - id: tx - leftPadding: NOO.factor() / 2 - font: rectButt.font - text: rectButt.text - color: checked ? "red" : activPal.text - scale: pressed ? 0.7 : 1.0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - } - - background: Rectangle { - id: bg - width: contentItem.width + NOO.factor() / 2 + id: rectButt + + property string statusTip: "" + property int statusPos: Item.TopLeft + property alias textColor: tx.color + //* Properties to handle Scorek glyphs which are out of rectangle + property alias forcedHeight: bg.height + property alias yOffset: tx.topPadding + height: parent.height - color: activPal.highlight - radius: height / 5 - scale: hovered ? 1 : 0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - } - - onHoveredChanged: { - if (GLOB.showHints && statusTip !== "") - NOO.setStatusTip(hovered ? statusTip : "", statusPos) - } - - onClicked: focus = false // keep focus free - do not lock up space key + hoverEnabled: true + onHoveredChanged: { + if (GLOB.showHints && statusTip !== "") + NOO.setStatusTip(hovered ? statusTip : "", statusPos); + + } + onClicked: focus = false // keep focus free - do not lock up space key + + contentItem: Text { + id: tx + + leftPadding: NOO.factor() / 2 + font: rectButt.font + text: rectButt.text + color: checked ? "red" : activPal.text + scale: pressed ? 0.7 : 1 + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + } + + background: Rectangle { + id: bg + + width: contentItem.width + NOO.factor() / 2 + height: parent.height + color: activPal.highlight + radius: height / 5 + scale: hovered ? 1 : 0 + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + } + } diff --git a/src/qml/shared/RhythmSelector.qml b/src/qml/shared/RhythmSelector.qml index 2755d0e1122f6c2300430a09239848973c2a48ac..ef1da5115e58a44054e72bced23d44840f155e31 100644 --- a/src/qml/shared/RhythmSelector.qml +++ b/src/qml/shared/RhythmSelector.qml @@ -2,107 +2,174 @@ * Copyright (C) 2018-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 +import Nootka.Dialogs 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 -import Nootka.Dialogs 1.0 +TrtmSelectorItem { + implicitWidth: NOO.factor() * 10 + implicitHeight: NOO.factor() * 20 + Component { + id: moreComp + + Rectangle { + height: NOO.factor() * 2 + width: NOO.factor() * 10 + color: enabled ? (ma.containsMouse ? activPal.highlight : activPal.button) : Qt.darker(disdPal.window, 1.2) + + Text { + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignHCenter + width: NOO.factor() * 10 + fontSizeMode: Text.HorizontalFit + text: qsTr("rhythmic groups") + " ⋮" + textFormat: Text.StyledText + color: enabled ? (ma.containsMouse ? activPal.highlightedText : activPal.buttonText) : disdPal.buttonText + + font { + bold: true + pixelSize: NOO.factor() + } + + } + + MouseArea { + id: ma + + anchors.fill: parent + hoverEnabled: true + onClicked: { + morePop.y = parent.y > 100 ? rtmList.height - morePop.height : rtmList.y; + morePop.open(); + } + } -TrtmSelectorItem { - implicitWidth: NOO.factor() * 10 - implicitHeight: NOO.factor() * 20 - - Component { - id: moreComp - Rectangle { - height: NOO.factor() * 2; width: NOO.factor() * 10 - color: enabled ? (ma.containsMouse ? activPal.highlight : activPal.button ): Qt.darker(disdPal.window, 1.2) - Text { - anchors.verticalCenter: parent.verticalCenter; horizontalAlignment: Text.AlignHCenter - width: NOO.factor() * 10; fontSizeMode: Text.HorizontalFit; font { bold: true; pixelSize: NOO.factor() } - text: qsTr("rhythmic groups") + " ⋮"; textFormat: Text.StyledText - color: enabled ? (ma.containsMouse ? activPal.highlightedText : activPal.buttonText) : disdPal.buttonText - } - MouseArea { - id: ma - anchors.fill: parent - hoverEnabled: true - onClicked: { - morePop.y = parent.y > 100 ? rtmList.height - morePop.height : rtmList.y - morePop.open() } - } + } - } - - ListView { - id: rtmList - clip: true - height: parent.height; width: parent.width - spacing: NOO.factor() / 10 - ScrollBar.vertical: ScrollBar { active: enabled; visible: active } - model: 35 - delegate: Component { - Rectangle { - height: NOO.factor() * 2.5; width: parent ? parent.width : 0 - color: enabled ? (index % 2 ? activPal.alternateBase : activPal.base) : Qt.darker(disdPal.window, 1.2) - MouseArea { - anchors.fill: parent - onClicked: userChangedGroup(index, !chBox.checked) + + ListView { + id: rtmList + + clip: true + height: parent.height + width: parent.width + spacing: NOO.factor() / 10 + model: 35 + header: moreComp + footer: moreComp + + ScrollBar.vertical: ScrollBar { + active: enabled + visible: active } - Row { - TcheckBox { - id: chBox - property int pow: Math.pow(2, index < 22 ? index : index - 22) - checked: (index < 22 && basicMask & pow) || (index > 21 && dotsMask & pow) - onClicked: userChangedGroup(index, checked) - } - Text { - font { pixelSize: NOO.factor() * 1.5; family: "Scorek" } - y: -font.pixelSize * 0.8 - text: getGroupText(index + 1) - color: enabled ? activPal.text : disdPal.text - } + + delegate: Component { + Rectangle { + height: NOO.factor() * 2.5 + width: parent ? parent.width : 0 + color: enabled ? (index % 2 ? activPal.alternateBase : activPal.base) : Qt.darker(disdPal.window, 1.2) + + MouseArea { + anchors.fill: parent + onClicked: userChangedGroup(index, !chBox.checked) + } + + Row { + TcheckBox { + id: chBox + + property int pow: Math.pow(2, index < 22 ? index : index - 22) + + checked: (index < 22 && basicMask & pow) || (index > 21 && dotsMask & pow) + onClicked: userChangedGroup(index, checked) + } + + Text { + y: -font.pixelSize * 0.8 + text: getGroupText(index + 1) + color: enabled ? activPal.text : disdPal.text + + font { + pixelSize: NOO.factor() * 1.5 + family: "Scorek" + } + + } + + } + + } + } - } + } - header: moreComp - footer: moreComp - } - - Popup { - id: morePop - x: rtmList.width - - margins: NOO.factor() - background: GlowRect { color: activPal.window; shadowRadius: NOO.factor() / 2 } - - scale: GLOB.useAnimations ? 0 : 1.0 - enter: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 1.0 }} - exit: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 0.0 }} - - Column { - spacing: NOO.factor() / 2 - Text { text: qsTr("Filters") + ":"; color: activPal.text; anchors.horizontalCenter: parent.horizontalCenter } - TcheckBox { - text: qsTr("basic rhythms") - checked: basicMask - onClicked: { - basicMask = checked ? 4194303 : 0 - rtmList.positionViewAtIndex(0, ListView.Beginning) - basicGroupChanged() + + Popup { + id: morePop + + x: rtmList.width + margins: NOO.factor() + scale: GLOB.useAnimations ? 0 : 1 + + Column { + spacing: NOO.factor() / 2 + + Text { + text: qsTr("Filters") + ":" + color: activPal.text + anchors.horizontalCenter: parent.horizontalCenter + } + + TcheckBox { + text: qsTr("basic rhythms") + checked: basicMask + onClicked: { + basicMask = checked ? 4.1943e+06 : 0; + rtmList.positionViewAtIndex(0, ListView.Beginning); + basicGroupChanged(); + } + } + + TcheckBox { + text: qsTr("rhythms with dots") + checked: dotsMask + onClicked: { + dotsMask = checked ? 16383 : 0; + rtmList.positionViewAtIndex(22, ListView.Beginning); + dotsGroupChanged(); + } + } + } - } - TcheckBox { - text: qsTr("rhythms with dots") - checked: dotsMask - onClicked: { - dotsMask = checked ? 16383 : 0 - rtmList.positionViewAtIndex(22, ListView.Beginning) - dotsGroupChanged() + + background: GlowRect { + color: activPal.window + shadowRadius: NOO.factor() / 2 + } + + enter: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 1 + } + } - } + + exit: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 0 + } + + } + } - } + } diff --git a/src/qml/shared/TcheckBox.qml b/src/qml/shared/TcheckBox.qml index fc288e80ec6d6a9b7a9c8fed9ce77e78b48929fb..c38a880d9adda2ba2b74ed64d530834e853ce73b 100755 --- a/src/qml/shared/TcheckBox.qml +++ b/src/qml/shared/TcheckBox.qml @@ -2,52 +2,76 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - CheckBox { - id: chB - property alias textColor: textItem.color - property alias textItem: textItem - - font.pixelSize: NOO.factor() - - indicator: TipRect { - implicitWidth: NOO.factor() * 1.75; implicitHeight: NOO.factor() * 1.75 - x: chB.leftPadding; y: (chB.height - height) / 2 - horizontalOffset: rised ? NOO.factor() / 8 : 0; verticalOffset: horizontalOffset - rised: !chB.down - color: chB.enabled ? activPal.base : Qt.darker(disdPal.window, 1.2) - scale: chB.pressed ? 0.9 : 1.0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - - Rectangle { - width: parent.width; height: parent.height / 7 - anchors.centerIn: parent - color: chB.enabled ? activPal.dimText : disdPal.text - rotation: 45; radius: height / 2 - visible: chB.checked + id: chB + + property alias textColor: textItem.color + property alias textItem: textItem + + font.pixelSize: NOO.factor() + + indicator: TipRect { + implicitWidth: NOO.factor() * 1.75 + implicitHeight: NOO.factor() * 1.75 + x: chB.leftPadding + y: (chB.height - height) / 2 + horizontalOffset: rised ? NOO.factor() / 8 : 0 + verticalOffset: horizontalOffset + rised: !chB.down + color: chB.enabled ? activPal.base : Qt.darker(disdPal.window, 1.2) + scale: chB.pressed ? 0.9 : 1 + + Rectangle { + width: parent.width + height: parent.height / 7 + anchors.centerIn: parent + color: chB.enabled ? activPal.dimText : disdPal.text + rotation: 45 + radius: height / 2 + visible: chB.checked + } + + Rectangle { + width: parent.width + height: parent.height / 7 + anchors.centerIn: parent + color: chB.enabled ? activPal.dimText : disdPal.text + rotation: 135 + radius: height / 2 + visible: chB.checked + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + } - Rectangle { - width: parent.width; height: parent.height / 7 - anchors.centerIn: parent - color: chB.enabled ? activPal.dimText : disdPal.text - rotation: 135; radius: height / 2 - visible: chB.checked + + contentItem: Text { + id: textItem + + y: (chB.height - height) / 2 + text: chB.text + topPadding: chB.font.pixelSize * 0.4 + leftPadding: indicator.width + chB.font.pixelSize / 2 + color: chB.enabled ? activPal.text : disdPal.text + style: chB.activeFocus ? Text.Sunken : Text.Normal + styleColor: activPal.highlight + + font { + pixelSize: chB.font.pixelSize + family: chB.font.family + } + } - } - - contentItem: Text { - id: textItem - y: (chB.height - height) / 2 - text: chB.text - topPadding: chB.font.pixelSize * 0.4 - leftPadding: indicator.width + chB.font.pixelSize / 2 - color: chB.enabled ? activPal.text : disdPal.text - font { pixelSize: chB.font.pixelSize; family: chB.font.family } - style: chB.activeFocus ? Text.Sunken : Text.Normal - styleColor: activPal.highlight - } + } diff --git a/src/qml/shared/TcomboBox.qml b/src/qml/shared/TcomboBox.qml index 2b3b6d9020570ad1e0a7b420034b0664c152bef5..e76eb65c7e8a992b15b075d0b53b93819e955ae8 100644 --- a/src/qml/shared/TcomboBox.qml +++ b/src/qml/shared/TcomboBox.qml @@ -2,116 +2,176 @@ * Copyright (C) 2019-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - ComboBox { - id: cb + id: cb - property alias radius: bg.radius + property alias radius: bg.radius + // private + property var lockList: [] - height: NOO.factor() * 2 - font.pixelSize: NOO.factor() - - scale: GLOB.useAnimations && cb.pressed ? 0.9 : 1.0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - - /** + /** * locks/unlocks @p itemNr among combo box delegates depending on @p state: * @p true - lock; @p false - unlock */ - function lock(itemNr, state) { - if (itemNr < lockList.length) - lockList[itemNr] = state - else - console.log("[TcomboBox] not such an item. FixMe!", itemNr) - } - - // private - property var lockList: [] - - onCountChanged: { - var loops = Math.max(count, lockList.length) - for (var i = 0; i < loops; i++) { - if (i < lockList.length) { - if (lockList.length < count) - lockList.splice(i, 1) + function lock(itemNr, state) { + if (itemNr < lockList.length) + lockList[itemNr] = state; else - lockList[i] = false - } else { - if (count > lockList.length) - lockList.push(false) - } + console.log("[TcomboBox] not such an item. FixMe!", itemNr); + } + + height: NOO.factor() * 2 + font.pixelSize: NOO.factor() + scale: GLOB.useAnimations && cb.pressed ? 0.9 : 1 + onCountChanged: { + var loops = Math.max(count, lockList.length); + for (var i = 0; i < loops; i++) { + if (i < lockList.length) { + if (lockList.length < count) + lockList.splice(i, 1); + else + lockList[i] = false; + } else { + if (count > lockList.length) + lockList.push(false); + + } + } + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + } - } - - delegate: ItemDelegate { - id: itDel - width: cb.width; height: NOO.factor() * 2.5 - hoverEnabled: true - enabled: !lockList[index] - background: Rectangle { - color: cb.currentIndex === index || itDel.down ? activPal.highlight : (itDel.hovered ? NOO.alpha(activPal.highlight, 70) : "transparent") + + delegate: ItemDelegate { + id: itDel + + width: cb.width + height: NOO.factor() * 2.5 + hoverEnabled: true + enabled: !lockList[index] + highlighted: cb.highlightedIndex === index + + background: Rectangle { + color: cb.currentIndex === index || itDel.down ? activPal.highlight : (itDel.hovered ? NOO.alpha(activPal.highlight, 70) : "transparent") + } + + contentItem: Text { + text: modelData + color: itDel.enabled ? (cb.currentIndex === index || itDel.down ? activPal.highlightedText : activPal.text) : disdPal.text + textFormat: Text.StyledText + verticalAlignment: Text.AlignVCenter + scale: GLOB.useAnimations && itDel.pressed ? 0.9 : 1 + + font { + pixelSize: cb.font.pixelSize + strikeout: !itDel.enabled + bold: cb.currentIndex === index + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + } + } + + indicator: Text { + x: cb.width - width * (NOO.isAndroid() || NOO.isMac() ? 1.2 : 1) + color: cb.enabled ? activPal.text : disdPal.text + text: "⋮" + anchors.verticalCenter: parent.verticalCenter + style: cb.activeFocus ? Text.Sunken : Text.Normal + styleColor: activPal.highlight + + font { + pixelSize: cb.height * 0.7 + bold: true + } + + } + contentItem: Text { - text: modelData - color: itDel.enabled ? (cb.currentIndex === index || itDel.down ? activPal.highlightedText : activPal.text) : disdPal.text - textFormat: Text.StyledText - verticalAlignment: Text.AlignVCenter - scale: GLOB.useAnimations && itDel.pressed ? 0.9 : 1.0 - font { pixelSize: cb.font.pixelSize; strikeout: !itDel.enabled; bold: cb.currentIndex === index } - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} + font: cb.font + leftPadding: cb.height / 3 + text: displayText + color: cb.enabled ? activPal.text : disdPal.text + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + style: cb.activeFocus ? Text.Sunken : Text.Normal + styleColor: activPal.highlight } - highlighted: cb.highlightedIndex === index - } - - indicator: Text { - x: cb.width - width * (NOO.isAndroid() || NOO.isMac() ? 1.2 : 1) - color: cb.enabled ? activPal.text : disdPal.text; text: "⋮" - font { pixelSize: cb.height * 0.7; bold: true } - anchors.verticalCenter: parent.verticalCenter - style: cb.activeFocus ? Text.Sunken : Text.Normal - styleColor: activPal.highlight - } - - contentItem: Text { - font: cb.font; leftPadding: cb.height / 3 - text: displayText; color: cb.enabled ? activPal.text : disdPal.text - verticalAlignment: Text.AlignVCenter; elide: Text.ElideRight - style: cb.activeFocus ? Text.Sunken : Text.Normal - styleColor: activPal.highlight - } - - background: GlowRect { - id: bg - color: cb.enabled ? activPal.button : Qt.darker(disdPal.window, 1.2) - radius: NOO.factor() / 6 - rised: !cb.pressed - } - - popup: Popup { - parent: cb.parent - x: cb.x; y: cb.y + cb.height + NOO.factor() / 4 - scale: GLOB.useAnimations ? 0.1 : 1.0 - padding: 0 - - width: cb.width - implicitHeight: contentItem.implicitHeight - transformOrigin: Item.Top - - contentItem: ListView { - clip: true - implicitHeight: Math.min(contentHeight, NOO.factor() * 15) // 6 items - model: cb.popup.visible ? cb.delegateModel : null - currentIndex: cb.highlightedIndex - - ScrollBar.vertical: ScrollBar { active: cb.delegateModel.count > 6 } + + background: GlowRect { + id: bg + + color: cb.enabled ? activPal.button : Qt.darker(disdPal.window, 1.2) + radius: NOO.factor() / 6 + rised: !cb.pressed + } + + popup: Popup { + parent: cb.parent + x: cb.x + y: cb.y + cb.height + NOO.factor() / 4 + scale: GLOB.useAnimations ? 0.1 : 1 + padding: 0 + width: cb.width + implicitHeight: contentItem.implicitHeight + transformOrigin: Item.Top + + contentItem: ListView { + clip: true + implicitHeight: Math.min(contentHeight, NOO.factor() * 15) // 6 items + model: cb.popup.visible ? cb.delegateModel : null + currentIndex: cb.highlightedIndex + + ScrollBar.vertical: ScrollBar { + active: cb.delegateModel.count > 6 + } + + } + + background: GlowRect { + shadowRadius: NOO.factor() / 2 + color: activPal.window + } + + enter: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 1 + } + + } + + exit: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 0 + } + + } + } - background: GlowRect { shadowRadius: NOO.factor() / 2; color: activPal.window } - enter: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 1 }} - exit: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 0 }} - } } diff --git a/src/qml/shared/TcomboEdit.qml b/src/qml/shared/TcomboEdit.qml index b688574fba2f66d0fb19ee51786ca27a8a7aa900..a51d107b8c23199e6e9e0b950b747d510dc849e2 100644 --- a/src/qml/shared/TcomboEdit.qml +++ b/src/qml/shared/TcomboEdit.qml @@ -2,30 +2,38 @@ * Copyright (C) 2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - TcomboBox { - id: comboEdit - - property alias maximumLength: tf.maximumLength - - implicitWidth: NOO.factor() * 15 - editable: true - radius: NOO.factor() / 3 - - contentItem: TextField { - id: tf - text: comboEdit.displayText - selectByMouse: true - selectedTextColor: activPal.highlightedText - selectionColor: activPal.highlight - background: Rectangle { - border { width: comboEdit.focus ? 2 : 0; color: activPal.highlight } - color: enabled ? activPal.base : Qt.darker(disdPal.window, 1.2) - radius: NOO.factor() / 3 + id: comboEdit + + property alias maximumLength: tf.maximumLength + + implicitWidth: NOO.factor() * 15 + editable: true + radius: NOO.factor() / 3 + + contentItem: TextField { + id: tf + + text: comboEdit.displayText + selectByMouse: true + selectedTextColor: activPal.highlightedText + selectionColor: activPal.highlight + + background: Rectangle { + color: enabled ? activPal.base : Qt.darker(disdPal.window, 1.2) + radius: NOO.factor() / 3 + + border { + width: comboEdit.focus ? 2 : 0 + color: activPal.highlight + } + + } + } - } + } diff --git a/src/qml/shared/TcuteButton.qml b/src/qml/shared/TcuteButton.qml index 05e084c88eacfef71236c8072299c560a013c115..c475a9d983b730dc03bc80ca1928e644ba1c9ade 100644 --- a/src/qml/shared/TcuteButton.qml +++ b/src/qml/shared/TcuteButton.qml @@ -2,40 +2,51 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - AbstractButton { - id: cutButt - font.pixelSize: NOO.factor() - focus: true - - property alias radius: bg.radius - property alias color: bg.color - property alias textColor: butText.color - property alias border: bg.border - - scale: GLOB.useAnimations && pressed ? 0.8 : (cutButt.checked ? 0.9 : 1.0) - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - - contentItem: Text { - id: butText - padding: NOO.factor() / 3 - font: cutButt.font - horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter - minimumPixelSize: 8 - fontSizeMode: Text.HorizontalFit - color: enabled ? (checked ? activPal.highlightedText : activPal.text) : disdPal.text - text: cutButt.text - style: cutButt.activeFocus ? Text.Sunken : Text.Normal - styleColor: activPal.highlight - } - - background: GlowRect { - id: bg - color: enabled ? (cutButt.checked ? activPal.highlight : activPal.button) : disdPal.button - rised: !cutButt.checked && !cutButt.pressed - } + id: cutButt + + property alias radius: bg.radius + property alias color: bg.color + property alias textColor: butText.color + property alias border: bg.border + + font.pixelSize: NOO.factor() + focus: true + scale: GLOB.useAnimations && pressed ? 0.8 : (cutButt.checked ? 0.9 : 1) + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + contentItem: Text { + id: butText + + padding: NOO.factor() / 3 + font: cutButt.font + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + minimumPixelSize: 8 + fontSizeMode: Text.HorizontalFit + color: enabled ? (checked ? activPal.highlightedText : activPal.text) : disdPal.text + text: cutButt.text + style: cutButt.activeFocus ? Text.Sunken : Text.Normal + styleColor: activPal.highlight + } + + background: GlowRect { + id: bg + + color: enabled ? (cutButt.checked ? activPal.highlight : activPal.button) : disdPal.button + rised: !cutButt.checked && !cutButt.pressed + } + } diff --git a/src/qml/shared/Tflickable.qml b/src/qml/shared/Tflickable.qml index e82c65c5cb3424bc939028bb5f686b4a65a3f276..34db6f619c21039b09b12ad2ebaceda8906000cf 100644 --- a/src/qml/shared/Tflickable.qml +++ b/src/qml/shared/Tflickable.qml @@ -5,9 +5,13 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 - Flickable { - clip: true - width: parent.width - ScrollBar.vertical: ScrollBar { active: false; visible: active } + clip: true + width: parent.width + + ScrollBar.vertical: ScrollBar { + active: false + visible: active + } + } diff --git a/src/qml/shared/Tframe.qml b/src/qml/shared/Tframe.qml index e783c2bcab5a991e67203484ad0077215b2316b7..42bdb8da910f4aa57480dace1689416307715fce 100644 --- a/src/qml/shared/Tframe.qml +++ b/src/qml/shared/Tframe.qml @@ -2,21 +2,28 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - /** * Common frame with custom background and palette-aware colors */ Frame { - property alias border: bg.border - property alias bgColor: bg.color - background: Rectangle { - id: bg - color: "transparent" - border { color: enabled ? activPal.text : disdPal.text; width: NOO.factor() * 0.1 } - radius: NOO.factor() * 0.75 - } + property alias border: bg.border + property alias bgColor: bg.color + + background: Rectangle { + id: bg + + color: "transparent" + radius: NOO.factor() * 0.75 + + border { + color: enabled ? activPal.text : disdPal.text + width: NOO.factor() * 0.1 + } + + } + } diff --git a/src/qml/shared/TiconButton.qml b/src/qml/shared/TiconButton.qml index d5c599239bc617367bf0f9e9f7929134c1b2e274..b03d32691bfcd4e3df2101f2d0079770b8617bed 100644 --- a/src/qml/shared/TiconButton.qml +++ b/src/qml/shared/TiconButton.qml @@ -2,57 +2,71 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - AbstractButton { - id: root - font.pixelSize: NOO.factor() - focus: true - - property alias radius: bg.radius - property alias color: bg.color - property alias pixmap: img.source - property alias iconHeight: img.sourceSize.height - - scale: GLOB.useAnimations && pressed ? 0.9 : 1.0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - - implicitWidth: contentItem.implicitWidth + NOO.factor() - implicitHeight: contentItem.implicitHeight - - contentItem: Item { - implicitWidth: img.width + NOO.factor() / (NOO.isAndroid() ? 2 : 1) + txt.implicitWidth - implicitHeight: (img.height ? img.height : NOO.factor() * 2) + NOO.factor() / (NOO.isAndroid() ? 4 : 2) - Image { - id: img - x: Math.max(NOO.factor() / 2, (root.width - parent.implicitWidth) / 2) - sourceSize.height: NOO.factor() * 2 - anchors.verticalCenter: parent.verticalCenter - scale: root.activeFocus ? 1.1 : 1.0 + id: root + + property alias radius: bg.radius + property alias color: bg.color + property alias pixmap: img.source + property alias iconHeight: img.sourceSize.height + + font.pixelSize: NOO.factor() + focus: true + scale: GLOB.useAnimations && pressed ? 0.9 : 1 + implicitWidth: contentItem.implicitWidth + NOO.factor() + implicitHeight: contentItem.implicitHeight + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + contentItem: Item { + implicitWidth: img.width + NOO.factor() / (NOO.isAndroid() ? 2 : 1) + txt.implicitWidth + implicitHeight: (img.height ? img.height : NOO.factor() * 2) + NOO.factor() / (NOO.isAndroid() ? 4 : 2) + + Image { + id: img + + x: Math.max(NOO.factor() / 2, (root.width - parent.implicitWidth) / 2) + sourceSize.height: NOO.factor() * 2 + anchors.verticalCenter: parent.verticalCenter + scale: root.activeFocus ? 1.1 : 1 + } + + Text { + id: txt + + x: img.x + img.width + NOO.factor() / 3 + width: Math.min(implicitWidth, root.width - img.width - NOO.factor()) + height: img.height ? img.height : NOO.factor() * 2 + font: root.font + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + minimumPixelSize: 8 + fontSizeMode: Text.Fit + anchors.verticalCenter: parent.verticalCenter + color: enabled ? (checked ? activPal.highlightedText : activPal.text) : disdPal.text + text: root.text + style: root.activeFocus ? Text.Sunken : Text.Normal + styleColor: activPal.highlight + } + } - Text { - id: txt - x: img.x + img.width + NOO.factor() / 3 - width: Math.min(implicitWidth, root.width - img.width - NOO.factor()) - height: img.height ? img.height : NOO.factor() * 2 - font: root.font - horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter - minimumPixelSize: 8; fontSizeMode: Text.Fit - anchors.verticalCenter: parent.verticalCenter - color: enabled ? (checked ? activPal.highlightedText : activPal.text) : disdPal.text - text: root.text - style: root.activeFocus ? Text.Sunken : Text.Normal - styleColor: activPal.highlight + + background: GlowRect { + id: bg + + color: enabled ? (root.checked ? activPal.highlight : activPal.button) : disdPal.button + rised: !root.checked && !root.pressed } - } - background: GlowRect { - id: bg - color: enabled ? (root.checked ? activPal.highlight : activPal.button) : disdPal.button - rised: !root.checked && !root.pressed - } } - diff --git a/src/qml/shared/Tile.qml b/src/qml/shared/Tile.qml index 45c6b6d6e4c8c35af5798332700ecf8186343e4c..e3ff42774ac4436ca3984eb586e4277aaa72e81d 100644 --- a/src/qml/shared/Tile.qml +++ b/src/qml/shared/Tile.qml @@ -2,64 +2,89 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ -import QtQuick 2.12 - import Nootka 1.0 +import QtQuick 2.12 /** * 12 is magical number of pixels that corresponds with tipbg.png image size and keeps the frame pretty at any circumstances */ BorderImage { - property alias description: descText.text - property alias descriptionColor: descText.color - property alias bgColor: bg.color - property alias bgBorder: bg.border - default property alias content: container.data - - anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined - - width: parent.width - height: (descText.text === "" ? 0 : descText.height + NOO.factor()) + container.height + NOO.factor() * (NOO.isAndroid() ? 1.5 : 2.5) - - Rectangle { // background - id: bg - x: 6; y: 6; width: parent.width - 12; height: parent.height - 12 - color: enabled ? Qt.lighter(activPal.window, 1.05) : Qt.darker(disdPal.window, 1.5) - gradient: Gradient { - GradientStop { position: 0.5; color: enabled ? Qt.lighter(bg.color, 1.05) : Qt.darker(disdPal.window, 1.5) } - GradientStop { position: 0.8; color: enabled ? Qt.lighter(bg.color, 0.95) : Qt.darker(disdPal.window, 1.75) } - } - radius: 6 - } - - border { left: 12; right: 12; bottom: 12; top: 12 } - horizontalTileMode: BorderImage.Stretch - verticalTileMode: BorderImage.Stretch - source: NOO.pix("tipbg") + property alias description: descText.text + property alias descriptionColor: descText.color + property alias bgColor: bg.color + property alias bgBorder: bg.border + default property alias content: container.data - Column { - spacing: NOO.factor() / 2 + anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined width: parent.width + height: (descText.text === "" ? 0 : descText.height + NOO.factor()) + container.height + NOO.factor() * (NOO.isAndroid() ? 1.5 : 2.5) + horizontalTileMode: BorderImage.Stretch + verticalTileMode: BorderImage.Stretch + source: NOO.pix("tipbg") + + // background + Rectangle { + id: bg + + x: 6 + y: 6 + width: parent.width - 12 + height: parent.height - 12 + color: enabled ? Qt.lighter(activPal.window, 1.05) : Qt.darker(disdPal.window, 1.5) + radius: 6 + + gradient: Gradient { + GradientStop { + position: 0.5 + color: enabled ? Qt.lighter(bg.color, 1.05) : Qt.darker(disdPal.window, 1.5) + } + + GradientStop { + position: 0.8 + color: enabled ? Qt.lighter(bg.color, 0.95) : Qt.darker(disdPal.window, 1.75) + } - Item { width: parent.width; height: NOO.factor() * (NOO.isAndroid() ? 0.25 : 0.5) } // spacer + } - Item { - id: container - width: parent.width - NOO.factor() - height: childrenRect.height } - Text { - id: descText - anchors.bottom: parent.Bottom - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width * 0.96 - font.pixelSize: NOO.factor() * 0.8 - textFormat: Text.RichText - horizontalAlignment: Text.AlignHCenter - color: enabled ? activPal.text : disdPal.text - wrapMode: Text.WordWrap + border { + left: 12 + right: 12 + bottom: 12 + top: 12 + } + + Column { + spacing: NOO.factor() / 2 + width: parent.width + + // spacer + Item { + width: parent.width + height: NOO.factor() * (NOO.isAndroid() ? 0.25 : 0.5) + } + + Item { + id: container + + width: parent.width - NOO.factor() + height: childrenRect.height + } + + Text { + id: descText + + anchors.bottom: parent.Bottom + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width * 0.96 + font.pixelSize: NOO.factor() * 0.8 + textFormat: Text.RichText + horizontalAlignment: Text.AlignHCenter + color: enabled ? activPal.text : disdPal.text + wrapMode: Text.WordWrap + } + } - } } diff --git a/src/qml/shared/TipRect.qml b/src/qml/shared/TipRect.qml index 50e232db40669f5c1a4cf6d06ec8ec7cfa5e8126..91e4df41c1e518e7b30144f7a14f60c39e0eaf99 100644 --- a/src/qml/shared/TipRect.qml +++ b/src/qml/shared/TipRect.qml @@ -2,38 +2,40 @@ * Copyright (C) 2017-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 Qt5Compat.GraphicalEffects +import QtQuick 2.12 Item { - property alias color: bg.color - property alias radius: bg.radius - property bool rised: true - property alias shadowRadius: shadow.radius - property alias shadowColor: shadow.color - property alias border: bg.border - property alias horizontalOffset: shadow.horizontalOffset - property alias verticalOffset: shadow.verticalOffset + property alias color: bg.color + property alias radius: bg.radius + property bool rised: true + property alias shadowRadius: shadow.radius + property alias shadowColor: shadow.color + property alias border: bg.border + property alias horizontalOffset: shadow.horizontalOffset + property alias verticalOffset: shadow.verticalOffset + + Rectangle { + id: bg + + anchors.fill: parent + color: activPal.base + radius: NOO.factor() / 3 + visible: false + clip: true + } + + DropShadow { + id: shadow - Rectangle { - id: bg - anchors.fill: parent - color: activPal.base - radius: NOO.factor() / 3 - visible: false - clip: true - } + anchors.fill: bg + horizontalOffset: rised ? NOO.factor() / 5 : 0 + verticalOffset: rised ? NOO.factor() / 5 : 0 + radius: 8 + samples: 1 + radius * 2 + color: activPal.shadow + source: bg + } - DropShadow { - id: shadow - anchors.fill: bg - horizontalOffset: rised ? NOO.factor() / 5 : 0 - verticalOffset: rised ? NOO.factor() / 5 : 0 - radius: 8.0 - samples: 1 + radius * 2 - color: activPal.shadow - source: bg - } } diff --git a/src/qml/shared/TlabelText.qml b/src/qml/shared/TlabelText.qml index 8fcddb6cfeae28d937da0092f2488c597c8189cd..7697f48e64b2f00851c8a755e4bc3e3d57540a88 100644 --- a/src/qml/shared/TlabelText.qml +++ b/src/qml/shared/TlabelText.qml @@ -4,9 +4,8 @@ import QtQuick 2.12 - -/** Text usually used in Tile for control label, it is vertically centered and palette aware */ +//* Text usually used in Tile for control label, it is vertically centered and palette aware Text { - anchors.verticalCenter: parent.verticalCenter; - color: enabled ? activPal.text : disdPal.text + anchors.verticalCenter: parent.verticalCenter + color: enabled ? activPal.text : disdPal.text } diff --git a/src/qml/shared/Tmenu.qml b/src/qml/shared/Tmenu.qml index 583670f505a40ba32a43fd4f11791a0336e6bce2..29fffef210f8e0e084739997d1556e80a2f572a0 100644 --- a/src/qml/shared/Tmenu.qml +++ b/src/qml/shared/Tmenu.qml @@ -2,17 +2,37 @@ * Copyright (C) 2018-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - Menu { - width: NOO.factor() * 20 - scale: GLOB.useAnimations ? 0.1 : 1.0 + width: NOO.factor() * 20 + scale: GLOB.useAnimations ? 0.1 : 1 + + background: GlowRect { + shadowRadius: NOO.factor() / 2 + color: activPal.window + } + + enter: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 1 + } + + } + + exit: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 0 + } - background: GlowRect { shadowRadius: NOO.factor() / 2; color: activPal.window } + } - enter: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 1 }} - exit: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 0 }} } diff --git a/src/qml/shared/Tmessage.qml b/src/qml/shared/Tmessage.qml index 6d6fc9ca469694bebab8ec48129c38eb9f30b259..3e6dec51db6b1223e4076aa7a7eeb4817e306945 100644 --- a/src/qml/shared/Tmessage.qml +++ b/src/qml/shared/Tmessage.qml @@ -2,33 +2,36 @@ * Copyright (C) 2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Dialogs 1.2 -import Nootka 1.0 - TpopupDialog { - property alias message: mText.text - property color accent: activPal.highlight - - bgColor: Qt.tint(activPal.base, NOO.alpha(accent, 20)) - border { color: accent; width: NOO.factor() / 4.0 } - glowRect.radius: NOO.factor() - visible: true; modal: true - - width: mText.width + NOO.factor() / 2 - height: mText.height + header.height + footer.height + NOO.factor() - - rejectButton.visible: false - acceptButton.text: NOO.TR("QPlatformTheme", "OK") - - Text { - id: mText - x: NOO.factor() //; y: (parent.height - height) / 2 - width: NOO.factor() * 40 - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } + property alias message: mText.text + property color accent: activPal.highlight + + bgColor: Qt.tint(activPal.base, NOO.alpha(accent, 20)) + glowRect.radius: NOO.factor() + visible: true + modal: true + width: mText.width + NOO.factor() / 2 + height: mText.height + header.height + footer.height + NOO.factor() + rejectButton.visible: false + acceptButton.text: NOO.TR("QPlatformTheme", "OK") + onClosed: destroy() + + border { + color: accent + width: NOO.factor() / 4 + } + + Text { + id: mText + + x: NOO.factor() //; y: (parent.height - height) / 2 + width: NOO.factor() * 40 + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + } - onClosed: destroy() } diff --git a/src/qml/shared/TpopupDialog.qml b/src/qml/shared/TpopupDialog.qml index e45a39db2826222b3c7f5eeed1f22750817814d3..bed84da89440308096d85aff397158758e3f91db 100644 --- a/src/qml/shared/TpopupDialog.qml +++ b/src/qml/shared/TpopupDialog.qml @@ -2,62 +2,121 @@ * Copyright (C) 2018-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - Dialog { - id: dialog - - property alias bgColor: glowRect.color - property alias shadowColor: glowRect.shadowColor - property alias rejectButton: rejectButton - property alias acceptButton: acceptButton - property alias border: glowRect.border - property alias caption: hText.text - property alias glowRect: glowRect - property alias footWidth: butRow.width - - width: parent.width * 0.8; height: parent.height * 0.8 - x: (parent.width - width) / 2; y: (parent.height - height) / 2 - background: GlowRect { id: glowRect; color: activPal.window; shadowColor: activPal.shadow; radius: NOO.factor() } - scale: GLOB.useAnimations ? 0 : 1.0 - enter: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 1.0 }} - exit: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 0 }} - - header: Rectangle { - color: "transparent" - width: parent.width; height: NOO.factor() * 2.2; radius: NOO.factor() / 4 - visible: hText.text !== "" - Text { - id: hText - width: parent.width - NOO.factor() - fontSizeMode: Text.HorizontalFit - anchors.centerIn: parent; horizontalAlignment: Text.AlignHCenter - color: activPal.text - font { pixelSize: NOO.factor() * 1.5; bold: true } + id: dialog + + property alias bgColor: glowRect.color + property alias shadowColor: glowRect.shadowColor + property alias rejectButton: rejectButton + property alias acceptButton: acceptButton + property alias border: glowRect.border + property alias caption: hText.text + property alias glowRect: glowRect + property alias footWidth: butRow.width + + width: parent.width * 0.8 + height: parent.height * 0.8 + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + scale: GLOB.useAnimations ? 0 : 1 + + background: GlowRect { + id: glowRect + + color: activPal.window + shadowColor: activPal.shadow + radius: NOO.factor() } - Rectangle { width: parent.width; height: 1; color: glowRect.border.color; y: parent.height } - } - - footer: Rectangle { - color: "transparent"; width: parent ? parent.width : 0; height: butRow.height; radius: NOO.factor() / 4 - Row { - id: butRow; spacing: parent.width / 10; padding: parent.height / 7 - anchors.horizontalCenter: parent.horizontalCenter - TiconButton { - id: rejectButton - pixmap: NOO.pix("exit"); text: NOO.TR("QShortcut", "Cancel") - onClicked: reject() - color: Qt.tint(activPal.button, NOO.alpha("red", NOO.isAndroid() ? 40 : 0)) - } - TiconButton { - id: acceptButton - pixmap: NOO.pix("check"); text: NOO.TR("QPlatformTheme", "Apply") - onClicked: accept() - color: Qt.tint(activPal.button, NOO.alpha("green", NOO.isAndroid() ? 40 : 0)) - } + + enter: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 1 + } + + } + + exit: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 0 + } + } - } + + header: Rectangle { + color: "transparent" + width: parent.width + height: NOO.factor() * 2.2 + radius: NOO.factor() / 4 + visible: hText.text !== "" + + Text { + id: hText + + width: parent.width - NOO.factor() + fontSizeMode: Text.HorizontalFit + anchors.centerIn: parent + horizontalAlignment: Text.AlignHCenter + color: activPal.text + + font { + pixelSize: NOO.factor() * 1.5 + bold: true + } + + } + + Rectangle { + width: parent.width + height: 1 + color: glowRect.border.color + y: parent.height + } + + } + + footer: Rectangle { + color: "transparent" + width: parent ? parent.width : 0 + height: butRow.height + radius: NOO.factor() / 4 + + Row { + id: butRow + + spacing: parent.width / 10 + padding: parent.height / 7 + anchors.horizontalCenter: parent.horizontalCenter + + TiconButton { + id: rejectButton + + pixmap: NOO.pix("exit") + text: NOO.TR("QShortcut", "Cancel") + onClicked: reject() + color: Qt.tint(activPal.button, NOO.alpha("red", NOO.isAndroid() ? 40 : 0)) + } + + TiconButton { + id: acceptButton + + pixmap: NOO.pix("check") + text: NOO.TR("QPlatformTheme", "Apply") + onClicked: accept() + color: Qt.tint(activPal.button, NOO.alpha("green", NOO.isAndroid() ? 40 : 0)) + } + + } + + } + } diff --git a/src/qml/shared/TprogressBar.qml b/src/qml/shared/TprogressBar.qml index 8df20af8282a03b7cc341899726afbfef2894e78..931748cc9320f6fbd7c72f1e09a17b50b4946cfe 100644 --- a/src/qml/shared/TprogressBar.qml +++ b/src/qml/shared/TprogressBar.qml @@ -2,52 +2,71 @@ * Copyright (C) 2019 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Window 2.12 -import Nootka 1.0 - ProgressBar { - id: control - - property real tickWidth: Screen.pixelDensity * 0.7 - property real tickGap: tickWidth * 1.2 - - hoverEnabled: true - - background: Rectangle { - width: control.width; height: control.height * 0.8; y: control.height * 0.1 - color: activPal.window - } - - contentItem: Item { - width: control.width; height: control.height * 0.8; y: control.height * 0.1 - - Repeater { - model: control.width / (tickGap + tickWidth) - Rectangle { - color: x <= control.position * control.width ? GLOB.correctColor : activPal.base - width: tickWidth - radius: tickWidth / 2 - height: parent.height - x: index * (tickGap + tickWidth) - } + id: control + + property real tickWidth: Screen.pixelDensity * 0.7 + property real tickGap: tickWidth * 1.2 + + hoverEnabled: true + + background: Rectangle { + width: control.width + height: control.height * 0.8 + y: control.height * 0.1 + color: activPal.window } - Rectangle { - id: percentRect - width: percentText.width; height: control.height - anchors.centerIn: parent - color: activPal.window - opacity: control.hovered ? 1 : 0 - Behavior on opacity { enabled: GLOB.useAnimations; PropertyAnimation {} } - Text { - id: percentText - anchors.centerIn: parent - font.pointSize: percentRect.height * 0.8 - text: " " + Math.round(control.position * 100) + " % " - } + contentItem: Item { + width: control.width + height: control.height * 0.8 + y: control.height * 0.1 + + Repeater { + model: control.width / (tickGap + tickWidth) + + Rectangle { + color: x <= control.position * control.width ? GLOB.correctColor : activPal.base + width: tickWidth + radius: tickWidth / 2 + height: parent.height + x: index * (tickGap + tickWidth) + } + + } + + Rectangle { + id: percentRect + + width: percentText.width + height: control.height + anchors.centerIn: parent + color: activPal.window + opacity: control.hovered ? 1 : 0 + + Text { + id: percentText + + anchors.centerIn: parent + font.pointSize: percentRect.height * 0.8 + text: " " + Math.round(control.position * 100) + " % " + } + + Behavior on opacity { + enabled: GLOB.useAnimations + + PropertyAnimation { + } + + } + + } + } - } + } diff --git a/src/qml/shared/TradioButton.qml b/src/qml/shared/TradioButton.qml index eab65196a3d5e89a9078d1134d9f543a482929e3..bb56d790de106dfcbe64535e28c04e68507f9bc1 100755 --- a/src/qml/shared/TradioButton.qml +++ b/src/qml/shared/TradioButton.qml @@ -2,45 +2,65 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - RadioButton { - id: rb - property alias textColor: content.color - property real textScale: 1.0 - - font.pixelSize: NOO.factor() - - indicator: TipRect { - implicitWidth: rb.font.pixelSize * 2; implicitHeight: rb.font.pixelSize * 2 - x: rb.leftPadding; y: (rb.height - height) / 2 - horizontalOffset: rised ? NOO.factor() / 8 : 0; verticalOffset: horizontalOffset - radius: implicitWidth / 2 - rised: !rb.down - color: rb.enabled ? activPal.base : Qt.darker(disdPal.window, 1.2) - scale: rb.pressed ? 0.8 : (rb.checked ? 0.9 : 1.0) - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - - Rectangle { - anchors.fill: parent - radius: width / 2; scale: 0.6 - color: rb.enabled ? activPal.dimText : disdPal.text - rotation: 45 - visible: rb.checked + id: rb + + property alias textColor: content.color + property real textScale: 1 + + font.pixelSize: NOO.factor() + + indicator: TipRect { + implicitWidth: rb.font.pixelSize * 2 + implicitHeight: rb.font.pixelSize * 2 + x: rb.leftPadding + y: (rb.height - height) / 2 + horizontalOffset: rised ? NOO.factor() / 8 : 0 + verticalOffset: horizontalOffset + radius: implicitWidth / 2 + rised: !rb.down + color: rb.enabled ? activPal.base : Qt.darker(disdPal.window, 1.2) + scale: rb.pressed ? 0.8 : (rb.checked ? 0.9 : 1) + + Rectangle { + anchors.fill: parent + radius: width / 2 + scale: 0.6 + color: rb.enabled ? activPal.dimText : disdPal.text + rotation: 45 + visible: rb.checked + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + } + + contentItem: Text { + id: content + + text: rb.text + topPadding: rb.font.pixelSize * 0.4 + leftPadding: indicator.width + rb.font.pixelSize / 2 + color: rb.enabled ? activPal.text : disdPal.text + style: rb.activeFocus ? Text.Sunken : Text.Normal + styleColor: activPal.highlight + + font { + pixelSize: rb.font.pixelSize * textScale + family: rb.font.family + } + } - } - - contentItem: Text { - id: content - text: rb.text - topPadding: rb.font.pixelSize * 0.4 - leftPadding: indicator.width + rb.font.pixelSize / 2 - color: rb.enabled ? activPal.text : disdPal.text - font { pixelSize: rb.font.pixelSize * textScale; family: rb.font.family } - style: rb.activeFocus ? Text.Sunken : Text.Normal - styleColor: activPal.highlight - } + } diff --git a/src/qml/shared/TrangeSlider.qml b/src/qml/shared/TrangeSlider.qml index 858e8d7d1699b6692c5a25b12a79b029a7a0d2f5..cddcf921f80503d37d8b62a5cd58a7d0964e54a4 100644 --- a/src/qml/shared/TrangeSlider.qml +++ b/src/qml/shared/TrangeSlider.qml @@ -2,61 +2,86 @@ * Copyright (C) 2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - RangeSlider { - id: sl - - background: Rectangle { - x: sl.leftPadding - y: sl.topPadding + sl.availableHeight / 2 - height / 2 - implicitWidth: NOO.factor() * 15; implicitHeight: NOO.factor() / 2 - width: sl.availableWidth; height: implicitHeight - radius: height / 2 - color: sl.enabled ? activPal.mid : disdPal.mid - border { width: sl.activeFocus ? 1 : 0; color: activPal.highlight } - - Rectangle { - x: sl.first.visualPosition * parent.width - width: (sl.second.visualPosition - sl.first.visualPosition) * parent.width; height: parent.height - color: sl.enabled ? activPal.highlight : disdPal.highlight - radius: parent.radius + id: sl + + background: Rectangle { + x: sl.leftPadding + y: sl.topPadding + sl.availableHeight / 2 - height / 2 + implicitWidth: NOO.factor() * 15 + implicitHeight: NOO.factor() / 2 + width: sl.availableWidth + height: implicitHeight + radius: height / 2 + color: sl.enabled ? activPal.mid : disdPal.mid + + border { + width: sl.activeFocus ? 1 : 0 + color: activPal.highlight + } + + Rectangle { + x: sl.first.visualPosition * parent.width + width: (sl.second.visualPosition - sl.first.visualPosition) * parent.width + height: parent.height + color: sl.enabled ? activPal.highlight : disdPal.highlight + radius: parent.radius + } + } - } - - first.handle: TipRect { - scale: NOO.isAndroid() && first.pressed ? 1.3 : 1 - x: sl.leftPadding + sl.first.visualPosition * (sl.availableWidth - width / 2) - y: sl.topPadding + sl.availableHeight / 2 - height / 2 - implicitWidth: NOO.factor() * 2; implicitHeight: NOO.factor() * 2 - radius: NOO.factor() - rised: !sl.first.pressed - color: sl.first.pressed ? activPal.highlight : activPal.button - Rectangle { - anchors.fill: parent; scale: 0.5 - radius: height / 2 - color: sl.activeFocus ? activPal.text : activPal.highlightedText - border { width: sl.activeFocus ? 1 : 0; color: activPal.highlight } + + first.handle: TipRect { + scale: NOO.isAndroid() && first.pressed ? 1.3 : 1 + x: sl.leftPadding + sl.first.visualPosition * (sl.availableWidth - width / 2) + y: sl.topPadding + sl.availableHeight / 2 - height / 2 + implicitWidth: NOO.factor() * 2 + implicitHeight: NOO.factor() * 2 + radius: NOO.factor() + rised: !sl.first.pressed + color: sl.first.pressed ? activPal.highlight : activPal.button + + Rectangle { + anchors.fill: parent + scale: 0.5 + radius: height / 2 + color: sl.activeFocus ? activPal.text : activPal.highlightedText + + border { + width: sl.activeFocus ? 1 : 0 + color: activPal.highlight + } + + } + } - } - - second.handle: TipRect { - scale: NOO.isAndroid() && second.pressed ? 1.3 : 1 - x: sl.leftPadding + sl.second.visualPosition * (sl.availableWidth - width / 2) - y: sl.topPadding + sl.availableHeight / 2 - height / 2 - implicitWidth: NOO.factor() * 2; implicitHeight: NOO.factor() * 2 - radius: NOO.factor() - rised: !sl.second.pressed - color: sl.second.pressed ? activPal.highlight : activPal.button - Rectangle { - anchors.fill: parent; scale: 0.5 - radius: height / 2 - color: sl.activeFocus ? activPal.text : activPal.highlightedText - border { width: sl.activeFocus ? 1 : 0; color: activPal.highlight } + + second.handle: TipRect { + scale: NOO.isAndroid() && second.pressed ? 1.3 : 1 + x: sl.leftPadding + sl.second.visualPosition * (sl.availableWidth - width / 2) + y: sl.topPadding + sl.availableHeight / 2 - height / 2 + implicitWidth: NOO.factor() * 2 + implicitHeight: NOO.factor() * 2 + radius: NOO.factor() + rised: !sl.second.pressed + color: sl.second.pressed ? activPal.highlight : activPal.button + + Rectangle { + anchors.fill: parent + scale: 0.5 + radius: height / 2 + color: sl.activeFocus ? activPal.text : activPal.highlightedText + + border { + width: sl.activeFocus ? 1 : 0 + color: activPal.highlight + } + + } + } - } -} +} diff --git a/src/qml/shared/Transpose.qml b/src/qml/shared/Transpose.qml index e4ea14350cf57b542b3932bf51d01fdfa94fcce8..937a11bce6aedd9aec50154ad9bd582c0e813ce8 100644 --- a/src/qml/shared/Transpose.qml +++ b/src/qml/shared/Transpose.qml @@ -2,117 +2,190 @@ * Copyright (C) 2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - Column { - /** @p outShift is the value of selected transposition */ - property int outShift: keyChB.checked ? NOO.keysDiff(initialKey, selectedKey) : shiftSpin.value * (upRadio.checked ? 1 : -1) - property bool outScaleToRest: toRestsCombo.currentIndex === 1 - property bool inInstrumentScale: limitCombo.currentIndex === 0 - property alias headerVisible: header.visible - property int initialKey: 0 - property int selectedKey: transKeyCombo.currentIndex - 7 - property alias currentKeyId: transKeyCombo.currentIndex - property alias toKey: keyChB.checked - property alias byInterval: semiChB.checked - - // private - property int shift: 0 - - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() - Text { id: header; text: qsTr("Transpose"); color: activPal.text } - Row { - spacing: NOO.factor() - TcheckBox { - id: keyChB - anchors.verticalCenter: parent.verticalCenter - text: qsTr("to key", "like: Transpose to key") - onToggled: { - if (keyChB.checked) - semiChB.checked = false - else - transKeyCombo.currentIndex = 7 - } - } - TcomboBox { - id: transKeyCombo - anchors.verticalCenter: parent.verticalCenter - enabled: keyChB.checked - model: NOO.keyComboModel() - width: NOO.factor() * 20 - currentIndex: initialKey + 7 - } - } - Row { + //* @p outShift is the value of selected transposition + property int outShift: keyChB.checked ? NOO.keysDiff(initialKey, selectedKey) : shiftSpin.value * (upRadio.checked ? 1 : -1) + property bool outScaleToRest: toRestsCombo.currentIndex === 1 + property bool inInstrumentScale: limitCombo.currentIndex === 0 + property alias headerVisible: header.visible + property int initialKey: 0 + property int selectedKey: transKeyCombo.currentIndex - 7 + property alias currentKeyId: transKeyCombo.currentIndex + property alias toKey: keyChB.checked + property alias byInterval: semiChB.checked + // private + property int shift: 0 + + anchors.horizontalCenter: parent.horizontalCenter spacing: NOO.factor() - TcheckBox { - id: semiChB - text: qsTr("by interval", "like: Transpose by interval") - anchors.verticalCenter: parent.verticalCenter - onToggled: { - if (semiChB.checked) - keyChB.checked = false - else - shift = 0 - } + + Text { + id: header + + text: qsTr("Transpose") + color: activPal.text } + Row { - id: transSemi - spacing: NOO.factor() - TspinBox { - id: shiftSpin - enabled: semiChB.checked - anchors.verticalCenter: parent.verticalCenter - from: 0; to: 12 - value: Math.abs(shift) - onValueChanged: shift = value * (upRadio.checked ? 1 : -1) - } - TlabelText { - enabled: semiChB.checked - text: NOO.TR("Transposition", "semitone(s)", "", shiftSpin.value) - FontMetrics { id: fm } - width: fm.boundingRect(NOO.TR("Transposition", "semitone(s)", "", 5) + " ").width - } - ButtonGroup { id: upDownGroup } - Column { - enabled: semiChB.checked - onEnabledChanged: { - upRadio.checked = enabled - if (!enabled) - downRadio.checked = false + spacing: NOO.factor() + + TcheckBox { + id: keyChB + + anchors.verticalCenter: parent.verticalCenter + text: qsTr("to key", "like: Transpose to key") + onToggled: { + if (keyChB.checked) + semiChB.checked = false; + else + transKeyCombo.currentIndex = 7; + } } - Row { - TlabelText { text: "\u2191"; font { pixelSize: NOO.factor() * 2.5; family: "Nootka" }} - TradioButton { id: upRadio; text: NOO.TR("Transposition", "up"); ButtonGroup.group: upDownGroup } + + TcomboBox { + id: transKeyCombo + + anchors.verticalCenter: parent.verticalCenter + enabled: keyChB.checked + model: NOO.keyComboModel() + width: NOO.factor() * 20 + currentIndex: initialKey + 7 } + + } + + Row { + spacing: NOO.factor() + + TcheckBox { + id: semiChB + + text: qsTr("by interval", "like: Transpose by interval") + anchors.verticalCenter: parent.verticalCenter + onToggled: { + if (semiChB.checked) + keyChB.checked = false; + else + shift = 0; + } + } + Row { - TlabelText { text: "\u2193"; font { pixelSize: NOO.factor() * 2.5; family: "Nootka" }} - TradioButton { id: downRadio; text: NOO.TR("Transposition", "down"); ButtonGroup.group: upDownGroup } + id: transSemi + + spacing: NOO.factor() + + TspinBox { + id: shiftSpin + + enabled: semiChB.checked + anchors.verticalCenter: parent.verticalCenter + from: 0 + to: 12 + value: Math.abs(shift) + onValueChanged: shift = value * (upRadio.checked ? 1 : -1) + } + + TlabelText { + enabled: semiChB.checked + text: NOO.TR("Transposition", "semitone(s)", "", shiftSpin.value) + width: fm.boundingRect(NOO.TR("Transposition", "semitone(s)", "", 5) + " ").width + + FontMetrics { + id: fm + } + + } + + ButtonGroup { + id: upDownGroup + } + + Column { + enabled: semiChB.checked + onEnabledChanged: { + upRadio.checked = enabled; + if (!enabled) + downRadio.checked = false; + + } + + Row { + TlabelText { + text: "\u2191" + + font { + pixelSize: NOO.factor() * 2.5 + family: "Nootka" + } + + } + + TradioButton { + id: upRadio + + text: NOO.TR("Transposition", "up") + ButtonGroup.group: upDownGroup + } + + } + + Row { + TlabelText { + text: "\u2193" + + font { + pixelSize: NOO.factor() * 2.5 + family: "Nootka" + } + + } + + TradioButton { + id: downRadio + + text: NOO.TR("Transposition", "down") + ButtonGroup.group: upDownGroup + } + + } + + } + } - } + } - } - TcomboBox { - id: limitCombo - x: NOO.factor() * 2 - enabled: keyChB.checked || semiChB.checked - width: NOO.factor() * 27 - model: [ qsTr("Limit notes to instrument scale"), qsTr("Limit notes to notation range") ] - } - Row { - spacing: NOO.factor() - Text { text: qsTr("Off-scale notes"); color: activPal.text; anchors.verticalCenter: parent.verticalCenter } + TcomboBox { - id: toRestsCombo - enabled: keyChB.checked || semiChB.checked - width: NOO.factor() * 20 - model: [ qsTr("raise or drop about octave"), qsTr("convert into rests") ] + id: limitCombo + + x: NOO.factor() * 2 + enabled: keyChB.checked || semiChB.checked + width: NOO.factor() * 27 + model: [qsTr("Limit notes to instrument scale"), qsTr("Limit notes to notation range")] } - } -} + Row { + spacing: NOO.factor() + Text { + text: qsTr("Off-scale notes") + color: activPal.text + anchors.verticalCenter: parent.verticalCenter + } + + TcomboBox { + id: toRestsCombo + + enabled: keyChB.checked || semiChB.checked + width: NOO.factor() * 20 + model: [qsTr("raise or drop about octave"), qsTr("convert into rests")] + } + + } + +} diff --git a/src/qml/shared/Transposition.qml b/src/qml/shared/Transposition.qml index d851b1e51204df6c0d6331d45d1b274e5199dd25..a3f965f936d3a311c1da2026f93cd51d19d4b773 100644 --- a/src/qml/shared/Transposition.qml +++ b/src/qml/shared/Transposition.qml @@ -2,51 +2,98 @@ * Copyright (C) 2017-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - Grid { - property int shift: 0 - property int outShift: shiftSpin.value * (upRadio.checked ? 1 : -1) // read shift from here + property int shift: 0 + property int outShift: shiftSpin.value * (upRadio.checked ? 1 : -1) // read shift from here - onShiftChanged: { - upRadio.checked = shift >= 0 - downRadio.checked = shift < 0 - } + onShiftChanged: { + upRadio.checked = shift >= 0; + downRadio.checked = shift < 0; + } + anchors.horizontalCenter: parent.horizontalCenter + horizontalItemAlignment: Grid.AlignHCenter + verticalItemAlignment: Grid.AlignVCenter + spacing: NOO.factor() + columns: parent.width < NOO.factor() * 50 ? 1 : 2 - anchors.horizontalCenter: parent.horizontalCenter - horizontalItemAlignment: Grid.AlignHCenter; verticalItemAlignment: Grid.AlignVCenter - spacing: NOO.factor() - columns: parent.width < NOO.factor() * 50 ? 1 : 2 + Row { + spacing: NOO.factor() + + TlabelText { + text: qsTr("Transposition") + } + + TspinBox { + id: shiftSpin + + anchors.verticalCenter: parent.verticalCenter + from: 0 + to: 24 + value: Math.abs(shift) + onValueChanged: shift = value * (upRadio.checked ? 1 : -1) + } + + TlabelText { + text: qsTr("semitone(s)", "", shiftSpin.value) + width: fm.boundingRect(NOO.TR("Transposition", "semitone(s)", "", 5) + " ").width + + FontMetrics { + id: fm + } + + } - Row { - spacing: NOO.factor() - TlabelText { text: qsTr("Transposition") } - TspinBox { - id: shiftSpin - anchors.verticalCenter: parent.verticalCenter - from: 0; to: 24 - value: Math.abs(shift) - onValueChanged: shift = value * (upRadio.checked ? 1 : -1) - } - TlabelText { - text: qsTr("semitone(s)", "", shiftSpin.value) - FontMetrics { id: fm } - width: fm.boundingRect(NOO.TR("Transposition", "semitone(s)", "", 5) + " ").width } - } - ButtonGroup { id: upDownGroup } - Column { - Row { - TlabelText { text: "\u2191"; font { pixelSize: NOO.factor() * 2.5; family: "Nootka" }} - TradioButton { id: upRadio; text: qsTr("up"); ButtonGroup.group: upDownGroup } + ButtonGroup { + id: upDownGroup } - Row { - TlabelText { text: "\u2193"; font { pixelSize: NOO.factor() * 2.5; family: "Nootka" }} - TradioButton { id: downRadio; text: qsTr("down"); ButtonGroup.group: upDownGroup } + + Column { + Row { + TlabelText { + text: "\u2191" + + font { + pixelSize: NOO.factor() * 2.5 + family: "Nootka" + } + + } + + TradioButton { + id: upRadio + + text: qsTr("up") + ButtonGroup.group: upDownGroup + } + + } + + Row { + TlabelText { + text: "\u2193" + + font { + pixelSize: NOO.factor() * 2.5 + family: "Nootka" + } + + } + + TradioButton { + id: downRadio + + text: qsTr("down") + ButtonGroup.group: upDownGroup + } + + } + } - } + } diff --git a/src/qml/shared/Tslider.qml b/src/qml/shared/Tslider.qml index 96fdff49240580f47f4cfe08b46af2c0c3b63812..c47f26f340b07a441b767c5a7ec498bea147a283 100644 --- a/src/qml/shared/Tslider.qml +++ b/src/qml/shared/Tslider.qml @@ -2,43 +2,60 @@ * Copyright (C) 2019-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - Slider { - id: sl - - background: Rectangle { - x: sl.leftPadding - y: sl.topPadding + sl.availableHeight / 2 - height / 2 - implicitWidth: NOO.factor() * 15; implicitHeight: NOO.factor() / 2 - width: sl.availableWidth; height: implicitHeight - radius: height / 2 - color: sl.enabled ? activPal.mid : disdPal.mid - border { width: sl.activeFocus ? 1 : 0; color: activPal.highlight } - - Rectangle { - width: sl.visualPosition * parent.width; height: parent.height - color: sl.enabled ? activPal.highlight : disdPal.highlight - radius: parent.radius + id: sl + + background: Rectangle { + x: sl.leftPadding + y: sl.topPadding + sl.availableHeight / 2 - height / 2 + implicitWidth: NOO.factor() * 15 + implicitHeight: NOO.factor() / 2 + width: sl.availableWidth + height: implicitHeight + radius: height / 2 + color: sl.enabled ? activPal.mid : disdPal.mid + + border { + width: sl.activeFocus ? 1 : 0 + color: activPal.highlight + } + + Rectangle { + width: sl.visualPosition * parent.width + height: parent.height + color: sl.enabled ? activPal.highlight : disdPal.highlight + radius: parent.radius + } + } - } - - handle: TipRect { - scale: NOO.isAndroid() && pressed ? 1.3 : 1 - x: sl.leftPadding + sl.visualPosition * (sl.availableWidth - width / 2) - y: sl.topPadding + sl.availableHeight / 2 - height / 2 - implicitWidth: NOO.factor() * 2; implicitHeight: NOO.factor() * 2 - radius: NOO.factor() - rised: !sl.pressed - color: sl.pressed ? activPal.highlight : activPal.button - Rectangle { - anchors.fill: parent; scale: 0.5 - radius: height / 2 - color: sl.activeFocus ? activPal.text : activPal.highlightedText - border { width: sl.activeFocus ? 1 : 0; color: activPal.highlight } + + handle: TipRect { + scale: NOO.isAndroid() && pressed ? 1.3 : 1 + x: sl.leftPadding + sl.visualPosition * (sl.availableWidth - width / 2) + y: sl.topPadding + sl.availableHeight / 2 - height / 2 + implicitWidth: NOO.factor() * 2 + implicitHeight: NOO.factor() * 2 + radius: NOO.factor() + rised: !sl.pressed + color: sl.pressed ? activPal.highlight : activPal.button + + Rectangle { + anchors.fill: parent + scale: 0.5 + radius: height / 2 + color: sl.activeFocus ? activPal.text : activPal.highlightedText + + border { + width: sl.activeFocus ? 1 : 0 + color: activPal.highlight + } + + } + } - } + } diff --git a/src/qml/shared/TspinBox.qml b/src/qml/shared/TspinBox.qml index 370c3d29b57890bb41906bca1413305345d39aa6..9f11e9f0850395c61448f29fe6941c457e64d422 100644 --- a/src/qml/shared/TspinBox.qml +++ b/src/qml/shared/TspinBox.qml @@ -2,69 +2,108 @@ * Copyright (C) 2019-2021 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Controls 2.12 -import Nootka 1.0 - SpinBox { - id: sb - - editable: true - height: sb.font.pixelSize * 2.5; width: sb.font.pixelSize * 10 - font.pixelSize: NOO.factor() - - contentItem: TextInput { - z: 2 - width: sb.width - 2 * sb.height - text: sb.textFromValue(sb.value, sb.locale) - - font: sb.font - color: sb.enabled ? activPal.text : disdPal.text - selectionColor: activPal.highlight - selectedTextColor: activPal.highlightedText - horizontalAlignment: Qt.AlignHCenter; verticalAlignment: Qt.AlignVCenter - - readOnly: !sb.editable - validator: sb.validator - inputMethodHints: Qt.ImhFormattedNumbersOnly - } - - background: Rectangle { - color: sb.enabled ? activPal.base : Qt.darker(disdPal.window, 1.2) - width: sb.width - sb.height; height: sb.height - sb.font.pixelSize / 4 - x: sb.height / 2; y: sb.font.pixelSize / 8 - border { width: sb.activeFocus ? 1 : 0; color: activPal.highlight } - } - - up.indicator: TipRect { - x: sb.mirrored ? 0 : sb.width - sb.height - implicitHeight: sb.height; implicitWidth: sb.height - color: sb.enabled ? activPal.button : Qt.darker(disdPal.window, 1.3) - rised: !sb.up.pressed - scale: sb.up.pressed ? 0.9 : 1.0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - Rectangle { - x: parent.width / 4; width: parent.width / 2; height: parent.height / 15; y: parent.height * 0.48 - color: sb.enabled ? (sb.activeFocus ? activPal.text : activPal.dimText) : disdPal.text + id: sb + + editable: true + height: sb.font.pixelSize * 2.5 + width: sb.font.pixelSize * 10 + font.pixelSize: NOO.factor() + + contentItem: TextInput { + z: 2 + width: sb.width - 2 * sb.height + text: sb.textFromValue(sb.value, sb.locale) + font: sb.font + color: sb.enabled ? activPal.text : disdPal.text + selectionColor: activPal.highlight + selectedTextColor: activPal.highlightedText + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + readOnly: !sb.editable + validator: sb.validator + inputMethodHints: Qt.ImhFormattedNumbersOnly } - Rectangle { - x: parent.width / 4; width: parent.width / 2; height: parent.height / 15; y: parent.height * 0.48 - color: sb.enabled ? (sb.activeFocus ? activPal.text : activPal.dimText) : disdPal.text - rotation: 90 + + background: Rectangle { + color: sb.enabled ? activPal.base : Qt.darker(disdPal.window, 1.2) + width: sb.width - sb.height + height: sb.height - sb.font.pixelSize / 4 + x: sb.height / 2 + y: sb.font.pixelSize / 8 + + border { + width: sb.activeFocus ? 1 : 0 + color: activPal.highlight + } + } - } - - down.indicator: TipRect { - x: sb.mirrored ? sb.width - sb.height : 0 - implicitHeight: sb.height; implicitWidth: sb.height - color: sb.enabled ? activPal.button : Qt.darker(disdPal.window, 1.3) - rised: !sb.down.pressed - scale: sb.down.pressed ? 0.9 : 1.0 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - Rectangle { - x: parent.width / 4; width: parent.width / 2; height: parent.height / 15; y: parent.height * 0.48 - color: sb.enabled ? (sb.activeFocus ? activPal.text : activPal.dimText) : disdPal.text + + up.indicator: TipRect { + x: sb.mirrored ? 0 : sb.width - sb.height + implicitHeight: sb.height + implicitWidth: sb.height + color: sb.enabled ? activPal.button : Qt.darker(disdPal.window, 1.3) + rised: !sb.up.pressed + scale: sb.up.pressed ? 0.9 : 1 + + Rectangle { + x: parent.width / 4 + width: parent.width / 2 + height: parent.height / 15 + y: parent.height * 0.48 + color: sb.enabled ? (sb.activeFocus ? activPal.text : activPal.dimText) : disdPal.text + } + + Rectangle { + x: parent.width / 4 + width: parent.width / 2 + height: parent.height / 15 + y: parent.height * 0.48 + color: sb.enabled ? (sb.activeFocus ? activPal.text : activPal.dimText) : disdPal.text + rotation: 90 + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + } - } + + down.indicator: TipRect { + x: sb.mirrored ? sb.width - sb.height : 0 + implicitHeight: sb.height + implicitWidth: sb.height + color: sb.enabled ? activPal.button : Qt.darker(disdPal.window, 1.3) + rised: !sb.down.pressed + scale: sb.down.pressed ? 0.9 : 1 + + Rectangle { + x: parent.width / 4 + width: parent.width / 2 + height: parent.height / 15 + y: parent.height * 0.48 + color: sb.enabled ? (sb.activeFocus ? activPal.text : activPal.dimText) : disdPal.text + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + } + } diff --git a/src/qml/shared/TtextField.qml b/src/qml/shared/TtextField.qml index c02a649e007ecd1f953af00a5dd553f8c83b13ed..dd391a803967c922456f99d02356d15d55815983 100644 --- a/src/qml/shared/TtextField.qml +++ b/src/qml/shared/TtextField.qml @@ -5,21 +5,27 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 - TextField { - id: tf + id: tf + + property alias bg: bg + + selectByMouse: true + selectedTextColor: activPal.highlightedText + selectionColor: activPal.highlight + placeholderTextColor: disdPal.text + color: enabled ? activPal.text : disdPal.text + + background: TipRect { + id: bg + + color: enabled ? activPal.base : Qt.darker(disdPal.window, 1.2) - property alias bg: bg + border { + width: tf.focus ? 1 : 0 + color: activPal.highlight + } - selectByMouse: true - selectedTextColor: activPal.highlightedText - selectionColor: activPal.highlight - placeholderTextColor: disdPal.text - color: enabled ? activPal.text : disdPal.text + } - background: TipRect { - id: bg - border { width: tf.focus ? 1 : 0; color: activPal.highlight } - color: enabled ? activPal.base : Qt.darker(disdPal.window, 1.2) - } } diff --git a/src/qml/sound/CountdownItem.qml b/src/qml/sound/CountdownItem.qml index 035565377d491c4d19584c4978e448343760f4da..2b74a010e17143183f100ff6a1ee7988f57017c2 100644 --- a/src/qml/sound/CountdownItem.qml +++ b/src/qml/sound/CountdownItem.qml @@ -2,49 +2,59 @@ * 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 Nootka 1.0 import "../" +import Nootka 1.0 +import QtQuick 2.12 TipRect { - id: cntDwnItem + id: cntDwnItem + + property int tickCount: 0 + // private + property int counter: 1 + + width: row.width + NOO.factor() * 4 + height: nootkaWindow.height / 10 + x: height * 2 + y: NOO.factor() / 2 + z: 100 + color: Qt.tint(activPal.text, NOO.alpha("#00a0a0", 100)) + visible: counter <= tickCount && (SOUND.listening || SOUND.playing) && SOUND.metroRunning + + Connections { + target: tempoBar + onCntChanged: { + if (SOUND.metroRunning) + counter++; + + } + } - property int tickCount: 0 + Row { + id: row - width: row.width + NOO.factor() * 4; height: nootkaWindow.height / 10 - x: height * 2; y: NOO.factor() / 2 - z: 100 - color: Qt.tint(activPal.text, NOO.alpha("#00a0a0", 100)) - visible: counter <= tickCount && (SOUND.listening || SOUND.playing) && SOUND.metroRunning + anchors.centerIn: parent + spacing: NOO.factor() * 2 - // private - property int counter: 1 + Repeater { + id: cntRep - Connections { - target: tempoBar - onCntChanged: { - if (SOUND.metroRunning) - counter++ - } - } - - Row { - id: row - anchors.centerIn: parent - spacing: NOO.factor() * 2 - Repeater { - id: cntRep - model: tickCount - Text { - y: height * 0.07 - color: index + 1 === counter ? activPal.highlight : activPal.base - text: index % tempoBar.countTo + 1 - font { pixelSize: cntDwnItem.height * 0.8; family: "Scorek" } - } - } - } + model: tickCount -} + Text { + y: height * 0.07 + color: index + 1 === counter ? activPal.highlight : activPal.base + text: index % tempoBar.countTo + 1 + + font { + pixelSize: cntDwnItem.height * 0.8 + family: "Scorek" + } + + } + } + } + +} diff --git a/src/qml/sound/IntonationBar.qml b/src/qml/sound/IntonationBar.qml index 52d25f1fc4ad7d224db00ed63df81b7f4530c9b9..62759f6f910bf15bbe755db330efec1e483f692c 100644 --- a/src/qml/sound/IntonationBar.qml +++ b/src/qml/sound/IntonationBar.qml @@ -2,65 +2,93 @@ * Copyright (C) 2017-2020 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.Window 2.12 -import Nootka 1.0 -import "../" +Item { + id: intoBar + property real deviation: 0 + property bool active: true + property alias pitchText: noteText.text + property real tickWidth: Screen.pixelDensity * 0.5 + property real tickGap: tickWidth * 1.4 -Item { - id: intoBar - - property real deviation: 0.0 - property bool active: true - property alias pitchText: noteText.text - - property real tickWidth: Screen.pixelDensity * 0.5 - property real tickGap: tickWidth * 1.4 - - TtickColors { id: tc; width: (intoBar.width - textWrap.width * 2) / 2; divisor: tickGap + tickWidth } - - Repeater { - id: iRepLeft - model: tc.width / tc.divisor - Rectangle { - color: active ? (deviation < 0 && iRepLeft.model - index <= (deviation * -2 * iRepLeft.model) ? tc.colorAt(iRepLeft.model - index) : activPal.text) : disdPal.text - width: tickWidth - radius: tickWidth / 2 - height: tickWidth * 1.5 + ((intoBar.height - tickWidth * 4) / iRepLeft.model) * (iRepLeft.model - index) - y: (parent.height - height) / 2 - x: (index * tickGap) + (index + 2) * tickWidth + TtickColors { + id: tc + + width: (intoBar.width - textWrap.width * 2) / 2 + divisor: tickGap + tickWidth } - } - - TipRect { - id: textWrap - width: height * 1.7; height: parent.height * 1; radius: height / 8 - color: Qt.tint(activPal.base, NOO.alpha(active ? (dev > 0 ? (dev > 0.3 ? "red" : (dev > 0.1 ? "yellow" : "lime")) : activPal.base) : disdPal.base, 50)) - Behavior on color { ColorAnimation { duration: 150 }} - anchors.top: parent.Top - x: (intoBar.width - width) / 2 - property real dev: Math.abs(deviation) - Text { - id: noteText - y: height * -0.26; x: (parent.width - width) / 2 - font { family: "Scorek"; pixelSize: parent.height * 0.8 } - color: activPal.text; textFormat: Text.StyledText + + Repeater { + id: iRepLeft + + model: tc.width / tc.divisor + + Rectangle { + color: active ? (deviation < 0 && iRepLeft.model - index <= (deviation * -2 * iRepLeft.model) ? tc.colorAt(iRepLeft.model - index) : activPal.text) : disdPal.text + width: tickWidth + radius: tickWidth / 2 + height: tickWidth * 1.5 + ((intoBar.height - tickWidth * 4) / iRepLeft.model) * (iRepLeft.model - index) + y: (parent.height - height) / 2 + x: (index * tickGap) + (index + 2) * tickWidth + } + + } + + TipRect { + id: textWrap + + property real dev: Math.abs(deviation) + + width: height * 1.7 + height: parent.height * 1 + radius: height / 8 + color: Qt.tint(activPal.base, NOO.alpha(active ? (dev > 0 ? (dev > 0.3 ? "red" : (dev > 0.1 ? "yellow" : "lime")) : activPal.base) : disdPal.base, 50)) + anchors.top: parent.Top + x: (intoBar.width - width) / 2 + + Text { + id: noteText + + y: height * -0.26 + x: (parent.width - width) / 2 + color: activPal.text + textFormat: Text.StyledText + + font { + family: "Scorek" + pixelSize: parent.height * 0.8 + } + + } + + Behavior on color { + ColorAnimation { + duration: 150 + } + + } + } - } - - Repeater { - id: iRepRight - model: tc.width / tc.divisor - Rectangle { - color: active ? (deviation > 0 && index <= (deviation * 2 * iRepRight.model) ? tc.colorAt(index) : activPal.text) : disdPal.text - width: tickWidth - radius: tickWidth / 2 - height: tickWidth * 1.5 + ((intoBar.height - tickWidth * 4) / iRepRight.model) * index - y: (parent.height - height) / 2 - x: textWrap.x + textWrap.width * 1.5 + (index * tickGap) + (index + 2) * tickWidth + + Repeater { + id: iRepRight + + model: tc.width / tc.divisor + + Rectangle { + color: active ? (deviation > 0 && index <= (deviation * 2 * iRepRight.model) ? tc.colorAt(index) : activPal.text) : disdPal.text + width: tickWidth + radius: tickWidth / 2 + height: tickWidth * 1.5 + ((intoBar.height - tickWidth * 4) / iRepRight.model) * index + y: (parent.height - height) / 2 + x: textWrap.x + textWrap.width * 1.5 + (index * tickGap) + (index + 2) * tickWidth + } + } - } } diff --git a/src/qml/sound/NotesDiffBar.qml b/src/qml/sound/NotesDiffBar.qml index ab6365d8fe8ea3431dbcd4f5aafade711d19e5c2..b4ee49ea90cb5408100c17b515a765694370ac93 100644 --- a/src/qml/sound/NotesDiffBar.qml +++ b/src/qml/sound/NotesDiffBar.qml @@ -2,61 +2,95 @@ * Copyright (C) 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 Nootka 1.0 -import "../" +TnotesBarItem { + id: nBar + expectedNote: score.note + z: score.z + y: score.y + score.height + width: score.width + height: nootkaWindow.height / 20 + Component.onCompleted: setAmbitus(GLOB.loNote(), GLOB.hiNote()) -TnotesBarItem { - id: nBar - - expectedNote: score.note - - z: score.z - y: score.y + score.height - width: score.width; height: nootkaWindow.height / 20 - - Rectangle { // background - z: -1 - anchors.fill: parent - color: NOO.alpha(activPal.window, 240) - } - - GlowRect { - color: Qt.tint(activPal.base, NOO.alpha((notesDiff === 0 ? GLOB.correctColor: GLOB.wrongColor), 50)) - x: expectedX; y: (parent.height - height) / 2 - width: nBar.height - NOO.factor() / 2; height: width - Text { - y: -height * 0.2; anchors.horizontalCenter: parent.horizontalCenter - font { family: "Scorek"; pixelSize: nBar.height / 2 } - color: activPal.text - text: expectedName + // background + Rectangle { + z: -1 + anchors.fill: parent + color: NOO.alpha(activPal.window, 240) } - } - - GlowRect { - visible: detectedX > 0 - color: activPal.base - x: detectedX; y: (parent.height - height) / 2 - width: nBar.height - NOO.factor() / 2; height: width - Text { - y: -height * 0.2; anchors.horizontalCenter: parent.horizontalCenter - font { family: "Scorek"; pixelSize: nBar.height / 2 } - color: activPal.text - text: detectedName + + GlowRect { + color: Qt.tint(activPal.base, NOO.alpha((notesDiff === 0 ? GLOB.correctColor : GLOB.wrongColor), 50)) + x: expectedX + y: (parent.height - height) / 2 + width: nBar.height - NOO.factor() / 2 + height: width + + Text { + y: -height * 0.2 + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + text: expectedName + + font { + family: "Scorek" + pixelSize: nBar.height / 2 + } + + } + } - scale: isPlaying ? 1.5 : 1 - Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - Behavior on x { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }} - } - Component.onCompleted: setAmbitus(GLOB.loNote(), GLOB.hiNote()) + GlowRect { + visible: detectedX > 0 + color: activPal.base + x: detectedX + y: (parent.height - height) / 2 + width: nBar.height - NOO.factor() / 2 + height: width + scale: isPlaying ? 1.5 : 1 + + Text { + y: -height * 0.2 + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.text + text: detectedName - Connections { - target: GLOB - onGuitarParamsChanged: setAmbitus(GLOB.loNote(), GLOB.hiNote()) - } + font { + family: "Scorek" + pixelSize: nBar.height / 2 + } + + } + + Behavior on scale { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + Behavior on x { + enabled: GLOB.useAnimations + + NumberAnimation { + duration: 150 + } + + } + + } + + Connections { + target: GLOB + onGuitarParamsChanged: setAmbitus(GLOB.loNote(), GLOB.hiNote()) + } } diff --git a/src/qml/sound/PitchView.qml b/src/qml/sound/PitchView.qml index 0364def9a7288eff5b1b4fdd8b56c7092d8d4722..dd17f5c21d54762e3e7e8da23517c843fe38963c 100644 --- a/src/qml/sound/PitchView.qml +++ b/src/qml/sound/PitchView.qml @@ -2,82 +2,102 @@ * Copyright (C) 2017-2020 by Tomasz Bojczuk (seelook@gmail.com) * * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ +import Nootka 1.0 import QtQuick 2.12 import QtQuick.Window 2.12 - -import Nootka 1.0 import "sound" - Item { - id: pitchView - - property alias volume : volBar.volume - property bool active: SOUND.listening && !SOUND.tunerMode - - signal paused() - - height: parent.height * 0.9 - width: parent.width * 0.43 - - // protected - property real tickWidth: Screen.pixelDensity * 0.5 - property real tickGap: tickWidth * 1.4 - - TempoBar { - id: tempoBar - visible: !GLOB.singleNoteMode && ((GLOB.rhythmsEnabled && !executor) || (executor && executor.showRtmView)) - y: parent.height * 0.05 - width: parent.width - tunerButt.width - NOO.factor() - height: parent.height * 0.45 - } - - RectButton { - id: tunerButt - visible: volBar.visible - x: parent.width - width - NOO.factor() / 2; y: parent.height * 0.04 - height: parent.height / 2 - enabled: !executor - textColor: enabled ? activPal.text : disdPal.text - text: GLOB.midAfreq + "Hz" - font { pixelSize: parent.height * 0.36; bold: true } - statusTip: qsTranslate("TempoBar", "Tuner") - onClicked: { - nootkaWindow.showDialog(7) // Nootka.Tuner - SOUND.startListen() + id: pitchView + + property alias volume: volBar.volume + property bool active: SOUND.listening && !SOUND.tunerMode + // protected + property real tickWidth: Screen.pixelDensity * 0.5 + property real tickGap: tickWidth * 1.4 + + signal paused() + + height: parent.height * 0.9 + width: parent.width * 0.43 + onPaused: { + SOUND.stoppedByUser = !SOUND.stoppedByUser; + if (SOUND.listening) + SOUND.stopListen(); + else + SOUND.startListen(false); } - } - - VolumeBar { - id: volBar - visible: !executor || executor.showPitchView - active: pitchView.active - y: parent.height * 0.55 - width: parent.width - micButt.width * 2 - height: parent.height * 0.45 - Shortcut { sequence: "M"; onActivated: pitchView.paused(); enabled: !executor || executor.showPitchView } + + TempoBar { + id: tempoBar + + visible: !GLOB.singleNoteMode && ((GLOB.rhythmsEnabled && !executor) || (executor && executor.showRtmView)) + y: parent.height * 0.05 + width: parent.width - tunerButt.width - NOO.factor() + height: parent.height * 0.45 + } + RectButton { - id: micButt - statusTip: qsTr("Start/stop pitch detection") + "<br><b>(M)</b>" - x: volBar.width + width * 0.5 - font { family: "Nootka"; pixelSize: volBar.height } - text: "r" - onClicked: pitchView.paused() - checked: SOUND.listening + id: tunerButt + + visible: volBar.visible + x: parent.width - width - NOO.factor() / 2 + y: parent.height * 0.04 + height: parent.height / 2 + enabled: !executor + textColor: enabled ? activPal.text : disdPal.text + text: GLOB.midAfreq + "Hz" + statusTip: qsTranslate("TempoBar", "Tuner") + onClicked: { + nootkaWindow.showDialog(7); // Nootka.Tuner + SOUND.startListen(); + } + + font { + pixelSize: parent.height * 0.36 + bold: true + } + + } + + VolumeBar { + id: volBar + + visible: !executor || executor.showPitchView + active: pitchView.active + y: parent.height * 0.55 + width: parent.width - micButt.width * 2 + height: parent.height * 0.45 + + Shortcut { + sequence: "M" + onActivated: pitchView.paused() + enabled: !executor || executor.showPitchView + } + + RectButton { + id: micButt + + statusTip: qsTr("Start/stop pitch detection") + "<br><b>(M)</b>" + x: volBar.width + width * 0.5 + text: "r" + onClicked: pitchView.paused() + checked: SOUND.listening + + font { + family: "Nootka" + pixelSize: volBar.height + } + + } + + } + + Timer { + repeat: true + interval: 75 + running: pitchView.active + onTriggered: volume = SOUND.inputVol() } - } - - onPaused: { - SOUND.stoppedByUser = !SOUND.stoppedByUser - if (SOUND.listening) - SOUND.stopListen() - else - SOUND.startListen(false) - } - - Timer { - repeat: true; interval: 75; running: pitchView.active - onTriggered: volume = SOUND.inputVol() - } } diff --git a/src/qml/sound/TempoBar.qml b/src/qml/sound/TempoBar.qml index ce8dbae0f3112e3e58d0f5163e778542fe6628da..276abf656e0b270d192f7a9579c838bcbda13fd5 100644 --- a/src/qml/sound/TempoBar.qml +++ b/src/qml/sound/TempoBar.qml @@ -2,171 +2,224 @@ * 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 Nootka 1.0 -import "../" +Item { + id: tempoBar + // private + property var tMenu: null + property int hiTick: -1 + property int cnt: 1 + property var hArray: [0.6, 0, 0.3, 0, 0.6] + property var gArray: ["\ue1d5", "\ue1d9", "\ue1d7", "\ue1d9", "\ue1d5"] + property int countTo: NOO.meter(score.meter).countTo() + property var preCountItem: null + // protected + property var beatModel: ["\ue1d5", "\ue1d7", "\ue1d5 \ue1e7", "\ue1d3"] + property real contW: metroText.width + cntBeforeBut.width + metroRow.width + loudTickButt.width + + Row { + width: parent.width + height: parent.height + spacing: (width - contW) / 4 - 1 + + RectButton { + id: metroText + + forcedHeight: parent.height + yOffset: parent.height * -0.7 + statusTip: qsTr("Tempo") + " - " + qsTr("beats per minute") + "<br>" + qsTr("Mouse wheel changes tempo promptly (also with %1 key). Click for more options.").arg(NOO.isMac() ? "CMD" : "CTRL") + text: beatModel[SOUND.beatUnit] + "=" + SOUND.tempo + + font { + family: "Scorek" + pixelSize: parent.height * 0.7 + } + + MouseArea { + anchors.fill: parent + onClicked: { + if (!tMenu) { + var c = Qt.createComponent("qrc:/sound/TempoMenu.qml"); + tMenu = c.createObject(tempoBar); + } + tMenu.open(); + } + onWheel: { + if (!SOUND.metroRunning) { + if (wheel.angleDelta.y > 0) + SOUND.tempo = SOUND.tempo + (wheel.modifiers & Qt.ControlModifier ? 10 : 1); + else if (wheel.angleDelta.y < 0) + SOUND.tempo = SOUND.tempo - (wheel.modifiers & Qt.ControlModifier ? 10 : 1); + } + } + } -Item { - id: tempoBar - - // private - property var tMenu: null - property int hiTick: -1 - property int cnt: 1 - property var hArray: [ 0.6, 0, 0.3, 0, 0.6] - property var gArray: [ "\ue1d5", "\ue1d9", "\ue1d7", "\ue1d9", "\ue1d5" ] - property int countTo: NOO.meter(score.meter).countTo() - property var preCountItem: null - - // protected - property var beatModel: [ "\ue1d5", "\ue1d7", "\ue1d5 \ue1e7", "\ue1d3" ] - property real contW: metroText.width + cntBeforeBut.width + metroRow.width + loudTickButt.width - - Row { - width: parent.width; height: parent.height - spacing: (width - contW) / 4 - 1 - RectButton { - id: metroText - forcedHeight: parent.height; yOffset: parent.height * -0.7 - statusTip: qsTr("Tempo") + " - " + qsTr("beats per minute") - + "<br>" + qsTr("Mouse wheel changes tempo promptly (also with %1 key). Click for more options.").arg(NOO.isMac() ? "CMD" : "CTRL") - font { family: "Scorek"; pixelSize: parent.height * 0.7 } - text: beatModel[SOUND.beatUnit] + "=" + SOUND.tempo - MouseArea { - anchors.fill: parent - onClicked: { - if (!tMenu) { - var c = Qt.createComponent("qrc:/sound/TempoMenu.qml") - tMenu = c.createObject(tempoBar) - } - tMenu.open() - } - onWheel: { - if (!SOUND.metroRunning) { - if (wheel.angleDelta.y > 0) - SOUND.tempo = SOUND.tempo + (wheel.modifiers & Qt.ControlModifier ? 10 : 1) - else if (wheel.angleDelta.y < 0) - SOUND.tempo = SOUND.tempo - (wheel.modifiers & Qt.ControlModifier ? 10 : 1) - } } - } - } - RectButton { - id: cntBeforeBut - enabled: !SOUND.metroRunning - font { family: "Nootka"; pixelSize: parent.height } - text: "\u0190" - statusTip: qsTr("Countdown before playing or listening.") - checked: SOUND.tickBeforePlay - textColor: checked ? "#00a0a0" : activPal.text - onClicked: SOUND.tickBeforePlay = !SOUND.tickBeforePlay - } + RectButton { + id: cntBeforeBut + + enabled: !SOUND.metroRunning + text: "\u0190" + statusTip: qsTr("Countdown before playing or listening.") + checked: SOUND.tickBeforePlay + textColor: checked ? "#00a0a0" : activPal.text + onClicked: SOUND.tickBeforePlay = !SOUND.tickBeforePlay + + font { + family: "Nootka" + pixelSize: parent.height + } - Row { - id: metroRow - enabled: !tMenu || tMenu.enableMetronome - height: tempoBar.height - spacing: height / (SOUND.tempo < 110 ? 5 : 2) - Repeater { - id: rep - model: 5 - Rectangle { - readonly property color bgColor: Qt.tint(activPal.window, NOO.alpha(activPal.base, 100)) - y: parent.height * (Math.abs(0.6 - hArray[index]) / 5) - width: parent.height * (0.9 - (Math.abs(0.6 - hArray[index]) / 3)); height: parent.height * 0.8 + hArray[index] * parent.height - radius: width / 2 - color: index === hiTick && timer.running && enabled ? (index === 0 || index === 4 ? "#00a0a0" : activPal.text) : bgColor - rotation: (index - 2) * 30 - visible: SOUND.tempo < 110 || index % 2 !== 1 - Text { // rhythm - visible: !enabled || (index !== hiTick || !SOUND.metroRunning) - font { pixelSize: parent.height * 0.8; family: "Scorek" } - color: enabled ? activPal.text : disdPal.text - text: gArray[index] - y: parent.height * -0.85 - x: (parent.width - width) / 2 - } - Text { // count - visible: timer.running && index === hiTick && (!tMenu || (tMenu.count && tMenu.enableMetronome)) - font { pixelSize: parent.height; family: "Scorek" } - color: activPal.base - text: cnt - y: parent.height * -1.2 - x: (parent.width - width) / 2 - } } - } - } - RectButton { - id: loudTickButt - enabled: !SOUND.metroRunning - font { family: "Nootka"; pixelSize: parent.height } - text: "\u018f" - statusTip: qsTr("Audible metronome") + ".<br>" + qsTr("Use earphones! Otherwise ticking will disturb proper pitch detection!") - checked: SOUND.tickDuringPlay - textColor: checked ? "#00a0a0" : activPal.text - onClicked: SOUND.tickDuringPlay = !SOUND.tickDuringPlay - } + Row { + id: metroRow + + enabled: !tMenu || tMenu.enableMetronome + height: tempoBar.height + spacing: height / (SOUND.tempo < 110 ? 5 : 2) + + Repeater { + id: rep + + model: 5 + + Rectangle { + readonly property color bgColor: Qt.tint(activPal.window, NOO.alpha(activPal.base, 100)) + + y: parent.height * (Math.abs(0.6 - hArray[index]) / 5) + width: parent.height * (0.9 - (Math.abs(0.6 - hArray[index]) / 3)) + height: parent.height * 0.8 + hArray[index] * parent.height + radius: width / 2 + color: index === hiTick && timer.running && enabled ? (index === 0 || index === 4 ? "#00a0a0" : activPal.text) : bgColor + rotation: (index - 2) * 30 + visible: SOUND.tempo < 110 || index % 2 !== 1 + + // rhythm + Text { + visible: !enabled || (index !== hiTick || !SOUND.metroRunning) + color: enabled ? activPal.text : disdPal.text + text: gArray[index] + y: parent.height * -0.85 + x: (parent.width - width) / 2 + + font { + pixelSize: parent.height * 0.8 + family: "Scorek" + } + + } + + // count + Text { + visible: timer.running && index === hiTick && (!tMenu || (tMenu.count && tMenu.enableMetronome)) + color: activPal.base + text: cnt + y: parent.height * -1.2 + x: (parent.width - width) / 2 + + font { + pixelSize: parent.height + family: "Scorek" + } + + } + + } + + } - Timer { - id: timer - running: tempoBar.visible && SOUND.metroRunning - repeat: true - interval: (SOUND.tempo < 110 ? 15000 : 30000) / SOUND.tempo - property real elap: 0 - property real lag: 0 - property int phase: 0 - onRunningChanged: { - if (running) { - elap = 0; lag = 0; phase = 0; hiTick = 4 - } else { - cnt = 1 // reset it here - countdown number depends on it when running } - } - onTriggered: { - var currTime = new Date().getTime() - if (elap > 0) { - elap = currTime - elap - lag += elap - interval + + RectButton { + id: loudTickButt + + enabled: !SOUND.metroRunning + text: "\u018f" + statusTip: qsTr("Audible metronome") + ".<br>" + qsTr("Use earphones! Otherwise ticking will disturb proper pitch detection!") + checked: SOUND.tickDuringPlay + textColor: checked ? "#00a0a0" : activPal.text + onClicked: SOUND.tickDuringPlay = !SOUND.tickDuringPlay + + font { + family: "Nootka" + pixelSize: parent.height + } + } - elap = currTime - interval = Math.max(((SOUND.tempo < 110 ? 15000 : 30000) / SOUND.tempo) - lag, 1) - lag = 0 - if ((phase + (SOUND.tempo < 110 ? 1 : 2)) % 4 === 0) { - if (cnt < countTo) - cnt++ - else - cnt = 1 + + Timer { + id: timer + + property real elap: 0 + property real lag: 0 + property int phase: 0 + + running: tempoBar.visible && SOUND.metroRunning + repeat: true + interval: (SOUND.tempo < 110 ? 15000 : 30000) / SOUND.tempo + onRunningChanged: { + if (running) { + elap = 0; + lag = 0; + phase = 0; + hiTick = 4; + } else { + cnt = 1; // reset it here - countdown number depends on it when running + } + } + onTriggered: { + var currTime = new Date().getTime(); + if (elap > 0) { + elap = currTime - elap; + lag += elap - interval; + } + elap = currTime; + interval = Math.max(((SOUND.tempo < 110 ? 15000 : 30000) / SOUND.tempo) - lag, 1); + lag = 0; + if ((phase + (SOUND.tempo < 110 ? 1 : 2)) % 4 === 0) { + if (cnt < countTo) + cnt++; + else + cnt = 1; + } + phase += SOUND.tempo < 110 ? 1 : 2; + if (phase > 7) + phase = 0; + + hiTick = Math.abs(phase - 4); + } } - phase += SOUND.tempo < 110 ? 1 : 2 - if (phase > 7) phase = 0 - hiTick = Math.abs(phase - 4) - } + + } + + MouseArea { + x: metroRow.x + y: metroRow.y + width: metroRow.width + height: metroRow.height + hoverEnabled: true + onEntered: NOO.setStatusTip(qsTr("Metronome"), Item.TopLeft) + onExited: NOO.setStatusTip("", Item.TopLeft) } - } - - MouseArea { - x: metroRow.x; y: metroRow.y; width: metroRow.width; height: metroRow.height - hoverEnabled: true - onEntered: NOO.setStatusTip(qsTr("Metronome"), Item.TopLeft) - onExited: NOO.setStatusTip("", Item.TopLeft) - } - - Connections { - target: SOUND - onCountdownPrepare: { - if (SOUND.tickBeforePlay && !GLOB.singleNoteMode) { - if (!preCountItem) { - var d = Qt.createComponent("qrc:/sound/CountdownItem.qml") - preCountItem = d.createObject(score) + + Connections { + target: SOUND + onCountdownPrepare: { + if (SOUND.tickBeforePlay && !GLOB.singleNoteMode) { + if (!preCountItem) { + var d = Qt.createComponent("qrc:/sound/CountdownItem.qml"); + preCountItem = d.createObject(score); + } + preCountItem.tickCount = tickCount; + preCountItem.counter = 1; + } } - preCountItem.tickCount = tickCount - preCountItem.counter = 1 - } } - } + } diff --git a/src/qml/sound/TempoMenu.qml b/src/qml/sound/TempoMenu.qml index f29e5b53fc7413dd6c90a0aaf356b2455e1549e3..b308ffd628fda33e14d1e967493b6dc3a95171f8 100644 --- a/src/qml/sound/TempoMenu.qml +++ b/src/qml/sound/TempoMenu.qml @@ -2,255 +2,385 @@ * 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 Nootka 1.0 -import ".." +Popup { + property alias enableMetronome: metroVisibleChB.checked + property alias count: countChB.checked + // private + property var beatFactor: [1, 2, 0.666667, 0.5] + readonly property string quantTip: qsTr("Detected rhythmic units are rounded (quantization). Shortest units require more rhythmical accuracy.") + property real lastTime: new Date().getTime() + signal accepted() -Popup { - property alias enableMetronome: metroVisibleChB.checked - property alias count: countChB.checked + function tapTempo() { + var currTime = new Date().getTime(); + if (currTime - lastTime < 1500) + tempoSpin.value = Math.round(60000 / (currTime - lastTime)); - margins: NOO.factor() + lastTime = currTime; + } - background: GlowRect { color: activPal.window; shadowRadius: NOO.factor() / 2 } + margins: NOO.factor() + scale: GLOB.useAnimations ? 0 : 1 + x: NOO.isAndroid() ? (nootkaWindow.width - width) / 2 : 0 + y: NOO.isAndroid() ? (nootkaWindow.height - height) / 2 : 0 + onAboutToShow: { + SOUND.stop(); + spaceShort.enabled = true; + tempoSpin.value = SOUND.tempo; + buTumb.currentIndex = SOUND.beatUnit; + } + onAboutToHide: { + SOUND.startListen(); + spaceShort.enabled = false; + SOUND.setMetronome(tempoSpin.value, buTumb.currentIndex); + } - scale: GLOB.useAnimations ? 0 : 1.0 - enter: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 1.0 }} - exit: Transition { enabled: GLOB.useAnimations; NumberAnimation { property: "scale"; to: 0.0 }} + Column { + // Row + //visible: NOO.isAndroid() + //width: parent.width + //height: NOO.factor() * 2.8 + //anchors.horizontalCenter: parent.horizontalCenter + //color: ma2.containsPress ? NOO.alpha(activPal.highlight, 50) : "transparent" + //Text { + //anchors.verticalCenter: parent.verticalCenter + //text: "\u018f"; font { family: "Nootka"; pixelSize: NOO.factor() * 2.5 } + //color: SOUND.tickDuringPlay ? "#00a0a0" : activPal.text + //} + //Text { + //anchors.verticalCenter: parent.verticalCenter + //x: NOO.factor() * 4; font.pixelSize: NOO.factor() + //text: NOO.TR("TempoBar", "Audible metronome") + //} + //MouseArea { + //id: ma2 + //anchors.fill: parent + //onClicked: SOUND.tickDuringPlay = !SOUND.tickDuringPlay + //onPressAndHold: NOO.setStatusTip(NOO.TR("TempoBar", "Audible metronome") + ".<br>" + NOO.TR("TempoBar", "Use earphones! Otherwise ticking will disturb proper pitch detection!")) + //onReleased: NOO.setStatusTip("") + //} + //Rectangle { color: activPal.text; width: parent.width; height: 1; anchors.bottom: parent.bottom } + //} - x: NOO.isAndroid() ? (nootkaWindow.width - width) / 2 : 0 - y: NOO.isAndroid() ? (nootkaWindow.height - height) / 2 : 0 + spacing: NOO.factor() / 2 - signal accepted() + Row { + spacing: NOO.factor() - // private - property var beatFactor: [ 1, 2, 0.66666666666, 0.5 ] - readonly property string quantTip: qsTr("Detected rhythmic units are rounded (quantization). Shortest units require more rhythmical accuracy.") + Tumbler { + id: buTumb - Column { - spacing: NOO.factor() / 2 + property int prevIndex: -1 - Row { - spacing: NOO.factor() - Tumbler { - id: buTumb - property int prevIndex: -1 + anchors.verticalCenter: parent.verticalCenter + height: NOO.factor() * 6 + width: NOO.factor() * 2 + model: ["\ue1d5", "\ue1d7", "\ue1d5 \ue1e7", "\ue1d3"] + visibleItemCount: 3 + wrap: true + currentIndex: SOUND.beatUnit + onCurrentIndexChanged: { + if (prevIndex > -1) + tempoSpin.value = Math.round(tempoSpin.value * (beatFactor[currentIndex] / beatFactor[prevIndex])); - background: TipRect { color: buTumb.enabled ? activPal.base : Qt.darker(disdPal.window, 1.2); radius: 0 } - anchors.verticalCenter: parent.verticalCenter - height: NOO.factor() * 6; width: NOO.factor() * 2 - model: [ "\ue1d5", "\ue1d7", "\ue1d5 \ue1e7", "\ue1d3" ] - visibleItemCount: 3; wrap: true - currentIndex: SOUND.beatUnit + prevIndex = currentIndex; + } - onCurrentIndexChanged: { - if (prevIndex > -1) - tempoSpin.value = Math.round(tempoSpin.value * (beatFactor[currentIndex] / beatFactor[prevIndex])) - prevIndex = currentIndex - } + MouseArea { + anchors.fill: parent + z: -1 + onWheel: { + var ci = buTumb.currentIndex; + if (wheel.angleDelta.y > 0) + ci--; + else if (wheel.angleDelta.y < 0) + ci++; + if (ci >= buTumb.count) + ci = 0; + else if (ci < 0) + ci = buTumb.count - 1; + buTumb.currentIndex = ci; + } + } + // Tumbler + + background: TipRect { + color: buTumb.enabled ? activPal.base : Qt.darker(disdPal.window, 1.2) + radius: 0 + } + + delegate: Rectangle { + color: index === buTumb.currentIndex ? activPal.highlight : activPal.base + opacity: 1 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) + + Text { + text: modelData + y: height * 0.325 + height: parent.height + width: parent.width + color: index === buTumb.currentIndex ? activPal.highlightedText : activPal.text + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + font { + pixelSize: parent.height * 0.75 + family: "Scorek" + } + + MouseArea { + anchors.fill: parent + onClicked: buTumb.currentIndex = index + } + + } + + } + + } + + Text { + anchors.verticalCenter: parent.verticalCenter + text: "=" + color: activPal.text + + font { + pixelSize: NOO.factor() * 2 + } - delegate: Rectangle { - color: index === buTumb.currentIndex ? activPal.highlight : activPal.base - opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) - Text { - text: modelData - y: height * 0.325; height: parent.height; width: parent.width - color: index === buTumb.currentIndex ? activPal.highlightedText : activPal.text - horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter - font { pixelSize: parent.height * 0.75; family: "Scorek" } - MouseArea { - anchors.fill: parent - onClicked: buTumb.currentIndex = index } - } + + Column { + anchors.verticalCenter: parent.verticalCenter + + Row { + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + Text { + text: qsTr("tempo") + font.pixelSize: NOO.factor() + color: activPal.text + anchors.verticalCenter: parent.verticalCenter + } + + TspinBox { + id: tempoSpin + + focus: false + from: 40 + to: Math.min(240, 180 * beatFactor[buTumb.currentIndex]) + editable: true + value: SOUND.tempo + } + + } + + Tslider { + focus: false + width: parent.width * 0.96 + anchors.horizontalCenter: parent.horizontalCenter + value: tempoSpin.value + from: 40 + to: tempoSpin.to + onValueChanged: tempoSpin.value = value + stepSize: 10 + } + + } + } - MouseArea { - anchors.fill: parent - z: -1 - onWheel: { - var ci = buTumb.currentIndex - if (wheel.angleDelta.y > 0) - ci-- - else if (wheel.angleDelta.y < 0) - ci++ - if (ci >= buTumb.count) - ci = 0 - else if (ci < 0) - ci = buTumb.count - 1 - buTumb.currentIndex = ci - } + TiconButton { + width: parent.width - NOO.factor() + text: qsTr("Tap tempo") + pixmap: NOO.pix("fingerpoint") + anchors.horizontalCenter: parent.horizontalCenter + onClicked: tapTempo() + focus: true } - } // Tumbler - Text { - anchors.verticalCenter: parent.verticalCenter - text: "=" - color: activPal.text - font { pixelSize: NOO.factor() * 2 } - } + TcheckBox { + id: metroVisibleChB - Column { - anchors.verticalCenter: parent.verticalCenter - Row { - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - Text { text: qsTr("tempo"); font.pixelSize: NOO.factor(); color: activPal.text; anchors.verticalCenter: parent.verticalCenter } - TspinBox { - id: tempoSpin - focus: false - from: 40; to: Math.min(240, 180 * beatFactor[buTumb.currentIndex]); editable: true - value: SOUND.tempo - } + visible: !NOO.isAndroid() + text: qsTr("Metronome visible") + checked: true } - Tslider { - focus: false - width: parent.width * 0.96 - anchors.horizontalCenter: parent.horizontalCenter - value: tempoSpin.value - from: 40; to: tempoSpin.to - onValueChanged: tempoSpin.value = value - stepSize: 10 + + TcheckBox { + id: countChB + + visible: !NOO.isAndroid() + x: NOO.factor() + enabled: metroVisibleChB.checked + text: qsTr("Count up") + checked: true } - } - } // Row + Rectangle { + visible: NOO.isAndroid() + width: parent.width + height: NOO.factor() * 2.8 + anchors.horizontalCenter: parent.horizontalCenter + color: ma.containsPress ? NOO.alpha(activPal.highlight, 50) : "transparent" - TiconButton { - width: parent.width - NOO.factor() - text: qsTr("Tap tempo") - pixmap: NOO.pix("fingerpoint") - anchors.horizontalCenter: parent.horizontalCenter - onClicked: tapTempo() - focus: true - } + Rectangle { + color: activPal.text + width: parent.width + height: 1 + y: -1 + } + + Text { + anchors.verticalCenter: parent.verticalCenter + text: "\u0190" + color: SOUND.tickBeforePlay ? "#00a0a0" : activPal.text + + font { + family: "Nootka" + pixelSize: NOO.factor() * 2.5 + } + + } + + Text { + anchors.verticalCenter: parent.verticalCenter + x: NOO.factor() * 4 + font.pixelSize: NOO.factor() + text: qsTr("Count up") + } + + MouseArea { + id: ma + + anchors.fill: parent + onClicked: SOUND.tickBeforePlay = !SOUND.tickBeforePlay + onPressAndHold: NOO.setStatusTip(NOO.TR("TempoBar", "Countdown before playing or listening.")) + onReleased: NOO.setStatusTip("") + } + + Rectangle { + color: activPal.text + width: parent.width + height: 1 + y: parent.height + NOO.factor() / 4 - 1 + } + + } + //Rectangle { TODO: Not yet implemented under Android + + Item { + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width + height: radioRow.height + enabled: !executor + + ButtonGroup { + buttons: radioRow.children + } + + MouseArea { + anchors.fill: parent + hoverEnabled: !NOO.isAndroid() + onEntered: NOO.setStatusTip(quantTip, Item.TopLeft) + onExited: NOO.setStatusTip("", Item.TopLeft) + onPressAndHold: { + if (NOO.isAndroid()) + NOO.setStatusTip(quantTip); + + } + onReleased: { + if (NOO.isAndroid()) + NOO.setStatusTip(""); + + } + } + + Row { + id: radioRow + + spacing: NOO.factor() + anchors.horizontalCenter: parent.horizontalCenter + + Text { + text: qsTr("round to:") + font.pixelSize: NOO.factor() + color: activPal.text + anchors.verticalCenter: parent.verticalCenter + } + + TradioButton { + id: radio16 + + text: "G" + textScale: 2 + checked: SOUND.quantization === 6 + onClicked: SOUND.quantization = 6 + onHoveredChanged: NOO.setStatusTip(hovered ? quantTip : "", Item.TopLeft) + + font { + family: "Nootka" + } + + } + + TradioButton { + id: radio8 + + text: "F" + textScale: 2 + checked: SOUND.quantization === 12 + onClicked: SOUND.quantization = 12 + onHoveredChanged: NOO.setStatusTip(hovered ? quantTip : "", Item.TopLeft) + + font { + family: "Nootka" + } + + } + + } + + } - TcheckBox { - id: metroVisibleChB - visible: !NOO.isAndroid() - text: qsTr("Metronome visible") - checked: true } - TcheckBox { - id: countChB - visible: !NOO.isAndroid() - x: NOO.factor() - enabled: metroVisibleChB.checked - text: qsTr("Count up") - checked: true + Shortcut { + id: spaceShort + + sequence: " " + onActivated: tapTempo() } - Rectangle { - visible: NOO.isAndroid() - width: parent.width - height: NOO.factor() * 2.8 - anchors.horizontalCenter: parent.horizontalCenter - color: ma.containsPress ? NOO.alpha(activPal.highlight, 50) : "transparent" - Rectangle { color: activPal.text; width: parent.width; height: 1; y: -1 } - Text { - anchors.verticalCenter: parent.verticalCenter - text: "\u0190"; font { family: "Nootka"; pixelSize: NOO.factor() * 2.5 } - color: SOUND.tickBeforePlay ? "#00a0a0" : activPal.text - } - Text { - anchors.verticalCenter: parent.verticalCenter - x: NOO.factor() * 4; font.pixelSize: NOO.factor() - text: qsTr("Count up") - } - MouseArea { - id: ma - anchors.fill: parent - onClicked: SOUND.tickBeforePlay = !SOUND.tickBeforePlay - onPressAndHold: NOO.setStatusTip(NOO.TR("TempoBar", "Countdown before playing or listening.")) - onReleased: NOO.setStatusTip("") - } - Rectangle { color: activPal.text; width: parent.width; height: 1; y: parent.height + NOO.factor() / 4 - 1 } + background: GlowRect { + color: activPal.window + shadowRadius: NOO.factor() / 2 } - //Rectangle { TODO: Not yet implemented under Android - //visible: NOO.isAndroid() - //width: parent.width - //height: NOO.factor() * 2.8 - //anchors.horizontalCenter: parent.horizontalCenter - //color: ma2.containsPress ? NOO.alpha(activPal.highlight, 50) : "transparent" - //Text { - //anchors.verticalCenter: parent.verticalCenter - //text: "\u018f"; font { family: "Nootka"; pixelSize: NOO.factor() * 2.5 } - //color: SOUND.tickDuringPlay ? "#00a0a0" : activPal.text - //} - //Text { - //anchors.verticalCenter: parent.verticalCenter - //x: NOO.factor() * 4; font.pixelSize: NOO.factor() - //text: NOO.TR("TempoBar", "Audible metronome") - //} - //MouseArea { - //id: ma2 - //anchors.fill: parent - //onClicked: SOUND.tickDuringPlay = !SOUND.tickDuringPlay - //onPressAndHold: NOO.setStatusTip(NOO.TR("TempoBar", "Audible metronome") + ".<br>" + NOO.TR("TempoBar", "Use earphones! Otherwise ticking will disturb proper pitch detection!")) - //onReleased: NOO.setStatusTip("") - //} - //Rectangle { color: activPal.text; width: parent.width; height: 1; anchors.bottom: parent.bottom } - //} - - Item { - ButtonGroup { buttons: radioRow.children } - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width; height: radioRow.height - enabled: !executor - MouseArea { - anchors.fill: parent; hoverEnabled: !NOO.isAndroid() - onEntered: NOO.setStatusTip(quantTip, Item.TopLeft) - onExited: NOO.setStatusTip("", Item.TopLeft) - onPressAndHold: { - if (NOO.isAndroid()) - NOO.setStatusTip(quantTip) - } - onReleased: { - if (NOO.isAndroid()) - NOO.setStatusTip("") - } - } - Row { - id: radioRow - spacing: NOO.factor() - anchors.horizontalCenter: parent.horizontalCenter - Text { text: qsTr("round to:"); font.pixelSize: NOO.factor(); color: activPal.text; anchors.verticalCenter: parent.verticalCenter } - TradioButton { - id: radio16 - font { family: "Nootka" } - text: "G"; textScale: 2.0 - checked: SOUND.quantization === 6 - onClicked: SOUND.quantization = 6 - onHoveredChanged: NOO.setStatusTip(hovered ? quantTip : "", Item.TopLeft) - } - TradioButton { - id: radio8 - font { family: "Nootka" } - text: "F"; textScale: 2.0 - checked: SOUND.quantization === 12 - onClicked: SOUND.quantization = 12 - onHoveredChanged: NOO.setStatusTip(hovered ? quantTip : "", Item.TopLeft) + + enter: Transition { + enabled: GLOB.useAnimations + + NumberAnimation { + property: "scale" + to: 1 } - } - } - } + } - onAboutToShow: { SOUND.stop(); spaceShort.enabled = true; tempoSpin.value = SOUND.tempo; buTumb.currentIndex = SOUND.beatUnit } - onAboutToHide: { SOUND.startListen(); spaceShort.enabled = false; SOUND.setMetronome(tempoSpin.value, buTumb.currentIndex) } + exit: Transition { + enabled: GLOB.useAnimations - Shortcut { id: spaceShort; sequence: " "; onActivated: tapTempo() } + NumberAnimation { + property: "scale" + to: 0 + } - property real lastTime: new Date().getTime() + } - function tapTempo() { - var currTime = new Date().getTime() - if (currTime - lastTime < 1500) - tempoSpin.value = Math.round(60000 / (currTime - lastTime)) - lastTime = currTime - } } diff --git a/src/qml/sound/TunerDialog.qml b/src/qml/sound/TunerDialog.qml index 4b13266a628233e07aacbb54da2cbf800a353fb9..33c66f820640bcbc38e3bed1588c18dfb900a5d4 100644 --- a/src/qml/sound/TunerDialog.qml +++ b/src/qml/sound/TunerDialog.qml @@ -2,209 +2,326 @@ * 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 QtQuick.Controls 2.12 - -import Nootka 1.0 -import Nootka.Dialogs 1.0 import "../" import "../settings" - +import Nootka 1.0 +import Nootka.Dialogs 1.0 +import QtQuick 2.12 +import QtQuick.Controls 2.12 TtunerDialogItem { - id: tunerDialog - width: parent.width; height: parent.height + id: tunerDialog - property bool widthEnough: dialLoader.width > dialLoader.height + property bool widthEnough: dialLoader.width > dialLoader.height - Drawer { - id: exDrawer - width: exCol.width + NOO.factor() * 2 + width: parent.width height: parent.height - visible: widthEnough; modal: false - closePolicy: widthEnough ? Popup.NoAutoClose : Popup.CloseOnEscape | Popup.CloseOnPressOutside - background: TipRect { color: activPal.base; radius: 0 } - Column { - id: exCol - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() * 1.5 - Item { width: NOO.factor(); height: NOO.factor() } - Repeater { - model: tuningModel - Row { - property var splitText: modelData.split(";") - Text { - visible: GLOB.instrument.isGuitar - anchors.verticalCenter: parent.verticalCenter - font { family: "Nootka"; pixelSize: NOO.factor() * 2.3 } - color: activPal.text; textFormat: Text.Normal - text: index + 1 - } - Item { - width: childrenRect.width; height: NOO.factor() * 1.5 - anchors.verticalCenter: parent.verticalCenter - Text { - y: -height * 0.34 - font { family: "Scorek"; pixelSize: NOO.factor() * 2 } - color: activPal.text; textFormat: Text.StyledText - text: splitText[0] - } - } - Text { - anchors.verticalCenter: parent.verticalCenter - font { family: "Nootka"; pixelSize: NOO.factor() * 1.2 } - color: activPal.text; textFormat: Text.Normal - text: "=" - } - Text { - anchors.verticalCenter: parent.verticalCenter - font { pixelSize: NOO.factor() * 1.4 } - color: activPal.text; textFormat: Text.Normal - text: splitText[1] - } - } - } - - Text { - width: parent.width - color: activPal.text - text: qsTranslate("SoundPage", "Frequency of detected note. You can use this for tuning.") - font.pixelSize: NOO.factor() * 0.8 - wrapMode: Text.WordWrap - } - } - } - - Column { - y: spacing - width: tunerDialog.width - (exDrawer.visible ? exDrawer.width : 0) - NOO.factor() - x: exDrawer.position * exDrawer.width + NOO.factor() / 2 - spacing: (parent.height - freqTile.height - pitchCol.height) / 3 - - MiddleA440 { - id: freqTile - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - NOO.factor() - value: GLOB.midAfreq - onValueChanged: workFreq = value + Component.onCompleted: { + dialLoader.standardButtons = DialogButtonBox.Close; + dialLoader.title = qsTr("Nooter - Nootka tuner"); } - Column { - id: pitchCol - spacing: NOO.factor() - width: parent.width - - Tumbler { - id: pitchTumb - width: parent.width; height: NOO.factor() * 4 - anchors.horizontalCenter: parent.horizontalCenter - visibleItemCount: ((width / (NOO.factor() * 5)) / 2) * 2 - 1 - model: highestNote() - lowestNote() - currentIndex: pitch - lowestNote() - wrap: false - delegate: Component { - Column { - spacing: NOO.factor() / 4 - opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) - scale: 1.7 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) + Drawer { + id: exDrawer + + width: exCol.width + NOO.factor() * 2 + height: parent.height + visible: widthEnough + modal: false + closePolicy: widthEnough ? Popup.NoAutoClose : Popup.CloseOnEscape | Popup.CloseOnPressOutside + + Column { + id: exCol + + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() * 1.5 + Item { - property int strNr: GLOB.instrument.isGuitar ? whichString(lowestNote() + modelData) : 0 - anchors.horizontalCenter: parent.horizontalCenter - Text { - visible: parent.strNr > 0 - x: strNameTxt.x + (strNameTxt.width - width) / 2 - text: parent.strNr > 0 ? parent.strNr : "" - font { family: "Nootka"; pixelSize: NOO.factor() * 1.5 } - property real dev: Math.abs(deviation) - color: pitchTumb.currentIndex === index ? (dev > 0 ? (dev > 0.3 ? "red" : (dev > 0.1 ? "yellow" : "lime")) : activPal.text) : activPal.text - Behavior on color { ColorAnimation { duration: 150 }} - y: pitchTumb.currentIndex === index ? 0 : -height / 2 - transformOrigin: Item.Top - scale: pitchTumb.currentIndex === index ? 1.6 : 1 - } - Text { - id: strNameTxt - visible: !GLOB.instrument.isGuitar || pitchTumb.currentIndex !== index - text: styledName(lowestNote() + modelData) + width: NOO.factor() + height: NOO.factor() + } + + Repeater { + model: tuningModel + + Row { + property var splitText: modelData.split(";") + + Text { + visible: GLOB.instrument.isGuitar + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + textFormat: Text.Normal + text: index + 1 + + font { + family: "Nootka" + pixelSize: NOO.factor() * 2.3 + } + + } + + Item { + width: childrenRect.width + height: NOO.factor() * 1.5 + anchors.verticalCenter: parent.verticalCenter + + Text { + y: -height * 0.34 + color: activPal.text + textFormat: Text.StyledText + text: splitText[0] + + font { + family: "Scorek" + pixelSize: NOO.factor() * 2 + } + + } + + } + + Text { + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + textFormat: Text.Normal + text: "=" + + font { + family: "Nootka" + pixelSize: NOO.factor() * 1.2 + } + + } + + Text { + anchors.verticalCenter: parent.verticalCenter + color: activPal.text + textFormat: Text.Normal + text: splitText[1] + + font { + pixelSize: NOO.factor() * 1.4 + } + + } + + } + + } + + Text { + width: parent.width color: activPal.text - y: height * -0.2; x: -width / 2 - font { family: "Scorek"; pixelSize: NOO.factor() * 1.5 } - } + text: qsTranslate("SoundPage", "Frequency of detected note. You can use this for tuning.") + font.pixelSize: NOO.factor() * 0.8 + wrapMode: Text.WordWrap } - } + } - contentItem: PathView { - id: pathView - interactive: false - model: pitchTumb.model - delegate: pitchTumb.delegate - pathItemCount: pitchTumb.visibleItemCount + 1 - preferredHighlightBegin: 0.5 - preferredHighlightEnd: 0.5 - path: Path { - startX: 0 - startY: NOO.factor() * 1.4 - PathLine { - x: pathView.width - y: NOO.factor() * 1.4 - } - } + + background: TipRect { + color: activPal.base + radius: 0 } - } - - IntonationBar { - id: intoBar - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - NOO.factor(); height: NOO.factor() * 3 - deviation: tunerDialog.deviation - pitchText: noteName - } - - Row { - id: freqTexts - x: (parent.width - width) / 2 + NOO.factor() * 2.5 // keep bg rect in the middle - spacing: NOO.factor() - TipRect { - width: NOO.factor() * 12; height: NOO.factor() * 3; radius: height / 8; color: activPal.base - Text { - anchors.centerIn: parent - font { pixelSize: NOO.factor() * 2; bold: true } - text: frequency; color: activPal.text - } + + } + + Column { + y: spacing + width: tunerDialog.width - (exDrawer.visible ? exDrawer.width : 0) - NOO.factor() + x: exDrawer.position * exDrawer.width + NOO.factor() / 2 + spacing: (parent.height - freqTile.height - pitchCol.height) / 3 + + MiddleA440 { + id: freqTile + + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - NOO.factor() + value: GLOB.midAfreq + onValueChanged: workFreq = value } - Text { - anchors.verticalCenter: parent.verticalCenter - font { pixelSize: NOO.factor() * 2 } - text: NOO.TR("SoundPage", "[Hz]") - color: activPal.text + + Column { + id: pitchCol + + spacing: NOO.factor() + width: parent.width + + Tumbler { + id: pitchTumb + + width: parent.width + height: NOO.factor() * 4 + anchors.horizontalCenter: parent.horizontalCenter + visibleItemCount: ((width / (NOO.factor() * 5)) / 2) * 2 - 1 + model: highestNote() - lowestNote() + currentIndex: pitch - lowestNote() + wrap: false + + delegate: Component { + Column { + spacing: NOO.factor() / 4 + opacity: 1 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) + scale: 1.7 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) + + Item { + property int strNr: GLOB.instrument.isGuitar ? whichString(lowestNote() + modelData) : 0 + + anchors.horizontalCenter: parent.horizontalCenter + + Text { + property real dev: Math.abs(deviation) + + visible: parent.strNr > 0 + x: strNameTxt.x + (strNameTxt.width - width) / 2 + text: parent.strNr > 0 ? parent.strNr : "" + color: pitchTumb.currentIndex === index ? (dev > 0 ? (dev > 0.3 ? "red" : (dev > 0.1 ? "yellow" : "lime")) : activPal.text) : activPal.text + y: pitchTumb.currentIndex === index ? 0 : -height / 2 + transformOrigin: Item.Top + scale: pitchTumb.currentIndex === index ? 1.6 : 1 + + font { + family: "Nootka" + pixelSize: NOO.factor() * 1.5 + } + + Behavior on color { + ColorAnimation { + duration: 150 + } + + } + + } + + Text { + id: strNameTxt + + visible: !GLOB.instrument.isGuitar || pitchTumb.currentIndex !== index + text: styledName(lowestNote() + modelData) + color: activPal.text + y: height * -0.2 + x: -width / 2 + + font { + family: "Scorek" + pixelSize: NOO.factor() * 1.5 + } + + } + + } + + } + + } + + contentItem: PathView { + id: pathView + + interactive: false + model: pitchTumb.model + delegate: pitchTumb.delegate + pathItemCount: pitchTumb.visibleItemCount + 1 + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + + path: Path { + startX: 0 + startY: NOO.factor() * 1.4 + + PathLine { + x: pathView.width + y: NOO.factor() * 1.4 + } + + } + + } + + } + + IntonationBar { + id: intoBar + + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - NOO.factor() + height: NOO.factor() * 3 + deviation: tunerDialog.deviation + pitchText: noteName + } + + Row { + id: freqTexts + + x: (parent.width - width) / 2 + NOO.factor() * 2.5 // keep bg rect in the middle + spacing: NOO.factor() + + TipRect { + width: NOO.factor() * 12 + height: NOO.factor() * 3 + radius: height / 8 + color: activPal.base + + Text { + anchors.centerIn: parent + text: frequency + color: activPal.text + + font { + pixelSize: NOO.factor() * 2 + bold: true + } + + } + + } + + Text { + anchors.verticalCenter: parent.verticalCenter + text: NOO.TR("SoundPage", "[Hz]") + color: activPal.text + + font { + pixelSize: NOO.factor() * 2 + } + + } + + } + } - } + } - } - - TcuteButton { - x: NOO.factor() / 2; y: NOO.factor() / 2 - height: NOO.factor() * 3 - visible: !exDrawer.visible - font { pixelSize: NOO.factor() * 2; bold: true } - text: "⋮" - onClicked: exDrawer.open() - } - - Component.onCompleted: { - dialLoader.standardButtons = DialogButtonBox.Close - dialLoader.title = qsTr("Nooter - Nootka tuner") - } - - Connections { - target: SOUND - onVolumeUpPressed: { - if (NOO.isAndroid()) - volSlider.value++ + + TcuteButton { + x: NOO.factor() / 2 + y: NOO.factor() / 2 + height: NOO.factor() * 3 + visible: !exDrawer.visible + text: "⋮" + onClicked: exDrawer.open() + + font { + pixelSize: NOO.factor() * 2 + bold: true + } + } - onVolumeDownPressed: { - if (NOO.isAndroid()) - volSlider.value-- + + Connections { + target: SOUND + onVolumeUpPressed: { + if (NOO.isAndroid()) + volSlider.value++; + + } + onVolumeDownPressed: { + if (NOO.isAndroid()) + volSlider.value--; + + } } - } + } diff --git a/src/qml/sound/VolumeBar.qml b/src/qml/sound/VolumeBar.qml index 3219828be06027e546b0fea6ec9eb1fafe68454d..0428668b076115d463b42a417d4ce71f36ab39b2 100644 --- a/src/qml/sound/VolumeBar.qml +++ b/src/qml/sound/VolumeBar.qml @@ -2,77 +2,98 @@ * 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.Window 2.12 -import Nootka 1.0 -import "../" +Item { + id: volBar + property real volume: 0.05 + property bool active: true + property real tickWidth: Screen.pixelDensity * 0.5 + property real tickGap: tickWidth * 1.4 + property alias knobVisible: knob.visible -Item { - id: volBar - - property real volume: 0.05 - property bool active: true - property real tickWidth: Screen.pixelDensity * 0.5 - property real tickGap: tickWidth * 1.4 - property alias knobVisible: knob.visible - - TtickColors { id: tc; width: volBar.width - minVolText.width; divisor: tickGap + tickWidth } - - MouseArea { - id: area - anchors.fill: parent - hoverEnabled: true - acceptedButtons: active ? Qt.LeftButton : Qt.NoButton - onPositionChanged: { - if (pressedButtons && mouseX > vRep.itemAt(1).x && mouseX < vRep.itemAt(vRep.model - 2).x) { - var mv = (mouseX - minVolText.width) / tc.width - if (mv > 0.1 && mv < 0.9) - GLOB.minVolume = mv - } + TtickColors { + id: tc + + width: volBar.width - minVolText.width + divisor: tickGap + tickWidth } - onEntered: NOO.setStatusTip(qsTr("Volume level of input sound.") + (active ? "<br>" + qsTr("Drag a knob to adjust minimum input volume.") : ""), - Item.TopLeft) - onExited: NOO.setStatusTip("", Item.TopLeft) - } - - Text { - id: minVolText - anchors { top: parent.Top; left: parent.Left; verticalCenter: parent.verticalCenter } - text: " " + Math.round(GLOB.minVolume * 100) + "% " - color: active ? activPal.text : disdPal.text - font.pixelSize: parent.height / 2 - width: parent.height * 1.2 - } - - Repeater { - id: vRep - model: Math.max(tc.width / tc.divisor, 0) - Rectangle { - color: active ? (index < volume * vRep.model ? tc.colorAt(index) : activPal.text) : disdPal.text - width: index <= GLOB.minVolume * vRep.model ? tickWidth / 2 : tickWidth - radius: tickWidth / 2 - height: tickWidth * 1.5 + ((volBar.height - tickWidth * 4) / vRep.model) * index - y: (parent.height - height) / 2 - x: minVolText.width + (index * tickGap) + (index + 1) * tickWidth + + MouseArea { + id: area + + anchors.fill: parent + hoverEnabled: true + acceptedButtons: active ? Qt.LeftButton : Qt.NoButton + onPositionChanged: { + if (pressedButtons && mouseX > vRep.itemAt(1).x && mouseX < vRep.itemAt(vRep.model - 2).x) { + var mv = (mouseX - minVolText.width) / tc.width; + if (mv > 0.1 && mv < 0.9) + GLOB.minVolume = mv; + + } + } + onEntered: NOO.setStatusTip(qsTr("Volume level of input sound.") + (active ? "<br>" + qsTr("Drag a knob to adjust minimum input volume.") : ""), Item.TopLeft) + onExited: NOO.setStatusTip("", Item.TopLeft) } - } - - TipRect { - id: knob - scale: NOO.isAndroid() && area.pressed ? 1.3 : 1 - x: minVolText.width + GLOB.minVolume * tc.width - radius - y: (volBar.height - height) / 2 - horizontalOffset: area.pressed ? 0 : tickWidth - verticalOffset: horizontalOffset - visible: active && (NOO.isAndroid() || area.pressed || area.containsMouse) - height: volBar.height * 0.9; width: height; radius: height / 2 - color: activPal.highlight - Rectangle { - anchors.fill: parent; scale: 0.5 - radius: height / 2 - color: activPal.highlightedText + + Text { + id: minVolText + + text: " " + Math.round(GLOB.minVolume * 100) + "% " + color: active ? activPal.text : disdPal.text + font.pixelSize: parent.height / 2 + width: parent.height * 1.2 + + anchors { + top: parent.Top + left: parent.Left + verticalCenter: parent.verticalCenter + } + + } + + Repeater { + id: vRep + + model: Math.max(tc.width / tc.divisor, 0) + + Rectangle { + color: active ? (index < volume * vRep.model ? tc.colorAt(index) : activPal.text) : disdPal.text + width: index <= GLOB.minVolume * vRep.model ? tickWidth / 2 : tickWidth + radius: tickWidth / 2 + height: tickWidth * 1.5 + ((volBar.height - tickWidth * 4) / vRep.model) * index + y: (parent.height - height) / 2 + x: minVolText.width + (index * tickGap) + (index + 1) * tickWidth + } + } - } + + TipRect { + id: knob + + scale: NOO.isAndroid() && area.pressed ? 1.3 : 1 + x: minVolText.width + GLOB.minVolume * tc.width - radius + y: (volBar.height - height) / 2 + horizontalOffset: area.pressed ? 0 : tickWidth + verticalOffset: horizontalOffset + visible: active && (NOO.isAndroid() || area.pressed || area.containsMouse) + height: volBar.height * 0.9 + width: height + radius: height / 2 + color: activPal.highlight + + Rectangle { + anchors.fill: parent + scale: 0.5 + radius: height / 2 + color: activPal.highlightedText + } + + } + } diff --git a/src/qml/updater/TupdateSummary.qml b/src/qml/updater/TupdateSummary.qml index 51371cca42a19ce868efec959e718bf02a691252..d4f3653ef2c756ffc927ff3cafb3ef0d2d8369ec 100644 --- a/src/qml/updater/TupdateSummary.qml +++ b/src/qml/updater/TupdateSummary.qml @@ -2,131 +2,178 @@ * 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 QtQuick.Controls 2.12 - +import "../" import Nootka 1.0 import Nootka.Update 1.0 -import "../" - +import QtQuick 2.12 +import QtQuick.Controls 2.12 TupdateItem { - id: updateIt + id: updateIt - property string titleText: NOO.isAndroid() ? "" : qsTr("Updates") + property string titleText: NOO.isAndroid() ? "" : qsTr("Updates") - width: parent.width; height: parent.height - - Connections { - target: dialogObj - onUpdateSummary: { - console.log(version) - updateIt.version = version - updateIt.changes = changes - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() * (NOO.isAndroid() ? 0.25 : 1) - - Item { width: height; height: NOO.isAndroid() ? 0 : NOO.factor() } - - LinkText { - id: headText - visible: onlineIsNewer - width: updateIt.width - NOO.factor() - font { pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.5); bold: true } - text: onlineIsNewer ? qsTr("New Nootka %1 is available.").arg(version) + "<br>" - + qsTr("To get it, visit %1 Nootka site").arg("<a href=\"https://nootka.sourceforge.io/index.php/download/\">") + "</a>." : "" - wrapMode: Text.WordWrap; horizontalAlignment: Text.AlignHCenter + function accepted() { + dialLoader.close(); } - GlowRect { - width: updateIt.width - NOO.factor() * 2 - height: updateIt.height - upCol.height - (onlineIsNewer ? headText.height : 0) - NOO.factor() * (NOO.isAndroid() ? 1 : 4) - anchors.horizontalCenter: parent.horizontalCenter - color: activPal.base - Tflickable { - anchors.fill: parent - contentWidth: width; contentHeight: chText.height + NOO.factor() - LinkText { - id: chText - padding: NOO.factor() / 2 - width: updateIt.width - NOO.factor() * 2 - textFormat: Text.StyledText - text: changes - wrapMode: Text.WordWrap - horizontalAlignment: onlineIsNewer ? Text.AlignLeft : Text.AlignHCenter + width: parent.width + height: parent.height + + Connections { + target: dialogObj + onUpdateSummary: { + console.log(version); + updateIt.version = version; + updateIt.changes = changes; } - } } Column { - id: upCol - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) - TcheckBox { - id: checkChB anchors.horizontalCenter: parent.horizontalCenter - text: qsTranslate("TupdateRulesWdg", "check for Nootka updates") - checked: updateCheck - onToggled: updateCheck = checked - } - Tile { - enabled: checkChB.checked - width: checkRow.width + NOO.factor() * 2 - Row { - id: checkRow - anchors.horizontalCenter: parent.horizontalCenter - spacing: NOO.factor() * (NOO.isAndroid() ? 2 : 4) - - ButtonGroup { buttons: periodCol.children } - Column { - id: periodCol - spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) - TcheckBox { - id: dailyChB - text: qsTranslate("TupdateRulesWdg", "daily") - checked: rules.width === 0 - onToggled: rules = Qt.size(0, rules.height) - } - TcheckBox { - id: weeklyChB - text: qsTranslate("TupdateRulesWdg", "weekly") - checked: rules.width === 1 - onToggled: rules = Qt.size(1, rules.height) + spacing: NOO.factor() * (NOO.isAndroid() ? 0.25 : 1) + + Item { + width: height + height: NOO.isAndroid() ? 0 : NOO.factor() + } + + LinkText { + id: headText + + visible: onlineIsNewer + width: updateIt.width - NOO.factor() + text: onlineIsNewer ? qsTr("New Nootka %1 is available.").arg(version) + "<br>" + qsTr("To get it, visit %1 Nootka site").arg("<a href=\"https://nootka.sourceforge.io/index.php/download/\">") + "</a>." : "" + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + + font { + pixelSize: NOO.factor() * (NOO.isAndroid() ? 1 : 1.5) + bold: true } - TcheckBox { - id: monthlyChB - text: qsTranslate("TupdateRulesWdg", "monthly") - checked: rules.width > 1 - onToggled: rules = Qt.size(2, rules.height) + + } + + GlowRect { + width: updateIt.width - NOO.factor() * 2 + height: updateIt.height - upCol.height - (onlineIsNewer ? headText.height : 0) - NOO.factor() * (NOO.isAndroid() ? 1 : 4) + anchors.horizontalCenter: parent.horizontalCenter + color: activPal.base + + Tflickable { + anchors.fill: parent + contentWidth: width + contentHeight: chText.height + NOO.factor() + + LinkText { + id: chText + + padding: NOO.factor() / 2 + width: updateIt.width - NOO.factor() * 2 + textFormat: Text.StyledText + text: changes + wrapMode: Text.WordWrap + horizontalAlignment: onlineIsNewer ? Text.AlignLeft : Text.AlignHCenter + } + } - } - ButtonGroup { buttons: versionCol.children } - Column { - id: versionCol - anchors.verticalCenter: parent.verticalCenter + } + + Column { + id: upCol + + anchors.horizontalCenter: parent.horizontalCenter spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) + TcheckBox { - id: allChB - text: qsTranslate("TupdateRulesWdg", "all new versions") - checked: rules.height === 0 - onToggled: rules = Qt.size(rules.width, 0) + id: checkChB + + anchors.horizontalCenter: parent.horizontalCenter + text: qsTranslate("TupdateRulesWdg", "check for Nootka updates") + checked: updateCheck + onToggled: updateCheck = checked } - TcheckBox { - id: stableChB - text: qsTranslate("TupdateRulesWdg", "stable versions only") - checked: rules.height !== 0 - onToggled: rules = Qt.size(rules.width, 1) + + Tile { + enabled: checkChB.checked + width: checkRow.width + NOO.factor() * 2 + + Row { + id: checkRow + + anchors.horizontalCenter: parent.horizontalCenter + spacing: NOO.factor() * (NOO.isAndroid() ? 2 : 4) + + ButtonGroup { + buttons: periodCol.children + } + + Column { + id: periodCol + + spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) + + TcheckBox { + id: dailyChB + + text: qsTranslate("TupdateRulesWdg", "daily") + checked: rules.width === 0 + onToggled: rules = Qt.size(0, rules.height) + } + + TcheckBox { + id: weeklyChB + + text: qsTranslate("TupdateRulesWdg", "weekly") + checked: rules.width === 1 + onToggled: rules = Qt.size(1, rules.height) + } + + TcheckBox { + id: monthlyChB + + text: qsTranslate("TupdateRulesWdg", "monthly") + checked: rules.width > 1 + onToggled: rules = Qt.size(2, rules.height) + } + + } + + ButtonGroup { + buttons: versionCol.children + } + + Column { + id: versionCol + + anchors.verticalCenter: parent.verticalCenter + spacing: NOO.factor() * (NOO.isAndroid() ? 0.5 : 1) + + TcheckBox { + id: allChB + + text: qsTranslate("TupdateRulesWdg", "all new versions") + checked: rules.height === 0 + onToggled: rules = Qt.size(rules.width, 0) + } + + TcheckBox { + id: stableChB + + text: qsTranslate("TupdateRulesWdg", "stable versions only") + checked: rules.height !== 0 + onToggled: rules = Qt.size(rules.width, 1) + } + + } + + } + } - } + } - } + } - } - function accepted() { dialLoader.close() } } diff --git a/src/qml/updater/UpdaterPopup.qml b/src/qml/updater/UpdaterPopup.qml index dc56df94487e77cafcf0383ef8b9f2f99273a705..24e6400a63be552bd945191a10abf64b8f327558 100644 --- a/src/qml/updater/UpdaterPopup.qml +++ b/src/qml/updater/UpdaterPopup.qml @@ -2,23 +2,28 @@ * 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 Nootka 1.0 import "../" +import Nootka 1.0 +import QtQuick 2.12 TpopupDialog { - id: updatePopup + id: updatePopup + + rejectButton.visible: false + width: NOO.isAndroid() ? globalPage.width - NOO.factor() : globalPage.width * 0.8 + height: NOO.isAndroid() ? globalPage.height + NOO.factor() * 3 : globalPage.height * 0.9 + bgColor: Qt.tint(activPal.window, NOO.alpha("teal", 20)) + caption: updateSum.titleText + + border { + color: "teal" + width: NOO.factor() / 4 + } + + TupdateSummary { + id: updateSum - rejectButton.visible: false + height: parent.height + NOO.factor() + } - width: NOO.isAndroid() ? globalPage.width - NOO.factor() : globalPage.width * 0.8 - height: NOO.isAndroid() ? globalPage.height + NOO.factor() * 3 : globalPage.height * 0.9 - bgColor: Qt.tint(activPal.window, NOO.alpha("teal", 20)) - border { color: "teal"; width: NOO.factor() / 4.0 } - caption: updateSum.titleText - TupdateSummary { - id: updateSum - height: parent.height + NOO.factor() - } }