From 946a5726c4cbe637b6bafacfcc630460988f78fd Mon Sep 17 00:00:00 2001 From: SeeLook <seelook@gmail.com> Date: Fri, 7 Feb 2025 16:50:35 +0100 Subject: [PATCH] Format QML with qmlformat --- src/main.cpp | 4 - src/qml/+android/FlyItem.qml | 167 ++-- src/qml/+android/MainMenuMobile.qml | 712 ++++++++++------- src/qml/+android/StatusTip.qml | 95 ++- src/qml/about/AboutPage.qml | 160 ++-- src/qml/about/ChangesPage.qml | 53 +- src/qml/about/DonorsPage.qml | 219 +++--- src/qml/about/HelpPage.qml | 265 ++++--- src/qml/about/LicensePage.qml | 36 +- src/qml/about/QtPage.qml | 23 +- src/qml/about/SupportPage.qml | 310 +++++--- src/qml/about/SupportPopup.qml | 65 +- src/qml/about/TaboutNootka.qml | 45 +- src/qml/about/TextBackground.qml | 21 +- src/qml/exam/Certificate.qml | 295 +++++--- src/qml/exam/CorrectInstrAnim.qml | 190 ++++- src/qml/exam/CorrectNameAnim.qml | 161 +++- src/qml/exam/CorrectNoteAnim.qml | 129 +++- src/qml/exam/ExamExecutor.qml | 188 +++-- src/qml/exam/ExamResults.qml | 507 ++++++++----- src/qml/exam/ExamSettingsDialog.qml | 29 +- src/qml/exam/ExamSummary.qml | 495 +++++++----- src/qml/exam/ExamTip.qml | 163 ++-- src/qml/exam/QuestionTip.qml | 88 ++- src/qml/exam/ResultLabel.qml | 84 +- src/qml/exam/ResultTip.qml | 121 +-- src/qml/exam/StartExam.qml | 704 ++++++++++------- src/qml/exam/TsuggestExam.qml | 121 +-- src/qml/gotit/ExamFlow.qml | 384 ++++++---- src/qml/gotit/ExamOrExercise.qml | 98 ++- src/qml/gotit/GotIt.qml | 266 ++++--- src/qml/gotit/HandleScore.qml | 815 ++++++++++++++------ src/qml/gotit/ImportInfo.qml | 149 ++-- src/qml/gotit/NoteSelected.qml | 449 ++++++----- src/qml/gotit/SoundInfo.qml | 353 +++++---- src/qml/instruments/Bandoneon.qml | 452 ++++++----- src/qml/instruments/ExtraName.qml | 48 +- src/qml/instruments/Guitar.qml | 278 ++++--- src/qml/instruments/Instrument.qml | 100 ++- src/qml/instruments/InstrumentZoom.qml | 106 +-- src/qml/instruments/OutScaleTip.qml | 55 +- src/qml/instruments/Piano.qml | 271 ++++--- src/qml/instruments/PianoKeyBlack.qml | 35 +- src/qml/instruments/PianoKeyWhite.qml | 74 +- src/qml/instruments/Sax.qml | 400 +++++++--- src/qml/instruments/SaxFlap.qml | 44 +- src/qml/instruments/Ukulele.qml | 292 +++---- src/qml/level/AccidsPage.qml | 344 +++++---- src/qml/level/CurrentKeyTile.qml | 18 +- src/qml/level/EndOnTonicTile.qml | 26 +- src/qml/level/LevelCreator.qml | 107 +-- src/qml/level/LevelPreview.qml | 549 ++++++++------ src/qml/level/LevelValidationMessage.qml | 95 ++- src/qml/level/Levels.qml | 22 +- src/qml/level/LevelsPage.qml | 302 ++++---- src/qml/level/LevelsSelector.qml | 255 ++++--- src/qml/level/MaxIntervalTile.qml | 51 +- src/qml/level/MelodyListView.qml | 521 ++++++++----- src/qml/level/MelodyPage.qml | 451 ++++++----- src/qml/level/MelodyWrapper.qml | 420 ++++++---- src/qml/level/MeterSelector.qml | 111 +-- src/qml/level/NewerVersionPopup.qml | 59 +- src/qml/level/PreviewItem.qml | 108 +-- src/qml/level/QuestionsBox.qml | 186 +++-- src/qml/level/QuestionsPage.qml | 431 ++++++----- src/qml/level/RangePage.qml | 340 +++++---- src/qml/level/RemoveLevel.qml | 95 +-- src/qml/level/RhythmDiversityTile.qml | 48 +- src/qml/level/RhythmsPage.qml | 227 +++--- src/qml/nootini/AudioAnalyze.qml | 268 ++++--- src/qml/score/AddLine.qml | 8 +- src/qml/score/Clef.qml | 130 ++-- src/qml/score/ClefDrawer.qml | 2 +- src/qml/score/ControlBase.qml | 79 +- src/qml/score/ControlButton.qml | 115 +-- src/qml/score/DelControl.qml | 159 ++-- src/qml/score/DummyChord.qml | 102 ++- src/qml/score/KeySignature.qml | 222 +++--- src/qml/score/MelGenDialog.qml | 241 +++--- src/qml/score/MelodyImport.qml | 925 ++++++++++++++--------- src/qml/score/MelodyNameDialog.qml | 184 +++-- src/qml/score/MelodyPreview.qml | 178 +++-- src/qml/score/Meter.qml | 90 ++- src/qml/score/MeterDrawer.qml | 101 ++- src/qml/score/NoteAdd.qml | 113 +-- src/qml/score/NoteCursor.qml | 202 +++-- src/qml/score/NotePrompt.qml | 22 +- src/qml/score/Scordature.qml | 97 ++- src/qml/score/Score.qml | 282 ++++--- src/qml/score/ScoreCursor.qml | 26 +- src/qml/score/ScoreToolbox.qml | 425 ++++++----- src/qml/score/Staff.qml | 178 +++-- src/qml/score/Tie.qml | 26 +- src/qml/settings/ColorButton.qml | 55 +- src/qml/settings/ExamPage.qml | 563 ++++++++------ src/qml/settings/GlobalPage.qml | 544 ++++++++----- src/qml/settings/InstrumentPage.qml | 666 +++++++++------- src/qml/settings/KeySufixEdit.qml | 91 ++- src/qml/settings/MiddleA440.qml | 105 ++- src/qml/settings/ScorePage.qml | 695 ++++++++++------- src/qml/settings/Select7note.qml | 96 ++- src/qml/settings/SoundPage.qml | 643 +++++++++------- src/qml/settings/TbuttonBar.qml | 69 +- src/qml/settings/TsettingsDialog.qml | 83 +- src/qml/shared/ClefMenu.qml | 186 +++-- src/qml/shared/DivideMelody.qml | 38 +- src/qml/shared/GlowRect.qml | 47 +- src/qml/shared/HeadButton.qml | 168 ++-- src/qml/shared/InstrumentSelector.qml | 161 ++-- src/qml/shared/LinkText.qml | 17 +- src/qml/shared/MenuButton.qml | 218 +++--- src/qml/shared/NameStyleSelector.qml | 171 +++-- src/qml/shared/PagesDialog.qml | 287 ++++--- src/qml/shared/PaneButton.qml | 125 +-- src/qml/shared/RectButton.qml | 98 ++- src/qml/shared/RhythmSelector.qml | 247 +++--- src/qml/shared/TcheckBox.qml | 108 ++- src/qml/shared/TcomboBox.qml | 252 +++--- src/qml/shared/TcomboEdit.qml | 50 +- src/qml/shared/TcuteButton.qml | 75 +- src/qml/shared/Tflickable.qml | 12 +- src/qml/shared/Tframe.qml | 27 +- src/qml/shared/TiconButton.qml | 106 +-- src/qml/shared/Tile.qml | 117 +-- src/qml/shared/TipRect.qml | 60 +- src/qml/shared/TlabelText.qml | 7 +- src/qml/shared/Tmenu.qml | 34 +- src/qml/shared/Tmessage.qml | 51 +- src/qml/shared/TpopupDialog.qml | 163 ++-- src/qml/shared/TprogressBar.qml | 99 ++- src/qml/shared/TradioButton.qml | 92 ++- src/qml/shared/TrangeSlider.qml | 125 +-- src/qml/shared/Transpose.qml | 269 ++++--- src/qml/shared/Transposition.qml | 119 ++- src/qml/shared/Tslider.qml | 83 +- src/qml/shared/TspinBox.qml | 155 ++-- src/qml/shared/TtextField.qml | 32 +- src/qml/sound/CountdownItem.qml | 82 +- src/qml/sound/IntonationBar.qml | 132 ++-- src/qml/sound/NotesDiffBar.qml | 128 ++-- src/qml/sound/PitchView.qml | 158 ++-- src/qml/sound/TempoBar.qml | 355 +++++---- src/qml/sound/TempoMenu.qml | 556 ++++++++------ src/qml/sound/TunerDialog.qml | 489 +++++++----- src/qml/sound/VolumeBar.qml | 151 ++-- src/qml/updater/TupdateSummary.qml | 255 ++++--- src/qml/updater/UpdaterPopup.qml | 33 +- 147 files changed, 17420 insertions(+), 11388 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c01efcf5b..7a7b3672b 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 c84768ee3..77d0bd385 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 a6884196b..9bd025e32 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 e0c07e6b5..865d11c8b 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 610ef6ee2..cd451055b 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 89bf6ca60..594d7c0f8 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 4fe641437..ca9805859 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 53e64f370..bb122ec47 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 46ce759e9..c9072cf42 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 a8ea477d6..de5b53f7b 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 3881c9caa..5bfefdb0f 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 b98e8413f..330d498bb 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 0cfe4279a..f24cf5c8b 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 856ee93d9..a0c098fe7 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 c22312f02..1b2fe6545 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 18a0e9e0d..dc117b210 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 d26b67111..f642f536d 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 8834e232b..a2fbdfda9 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 4400f680c..8da9a3cba 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 7fdc61016..c6816e804 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 b8932ed49..654ce850e 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 750658c7f..f2a50f1ce 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 d77355104..31767649f 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 b73894f28..a1ec08e89 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 248f80fa6..2b91532ce 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 54873ff6f..a17d18908 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 d884a8722..d7f285956 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 b168c4ab3..e4309bfe4 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 9ee04a015..10e323828 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 968b04dd7..d037f429a 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 d8bc533c5..8cb420141 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 98ec345ae..93dbc7fa9 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 ce2da6fc1..1e5a77d6e 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 26dbece1d..b77acc237 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 f7533ab65..b2725edde 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 cf4af7bdf..33cd61b8f 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 4761a392b..dfdc38e9f 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 f95305b85..c51e9ea41 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 ab1349523..0f529fbdf 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 25a5ea943..990873a17 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 66b9ffa7c..832d1d5d0 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 f95c5cd4d..b8e6cc70a 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 7f803ab6d..05d0c8344 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 64b98a350..11768b9b6 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 1ab906cbe..f112a1490 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 e3b9bd578..efebb3ac2 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 5464d65b2..480d6ffa8 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 286165f4c..c5528bfc8 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 9a4c02730..cc4812118 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 8b850420e..2cf7bc22a 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 ad4b02d0f..21874f4d0 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 357717f0c..06b5be004 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 070edaf5a..f3ea7186e 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 226f7eaec..40886c633 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 23ce031a4..353bb81a3 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 a380277aa..006c315ea 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 034ec08c3..e0356893c 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 d9cc1920a..9f4a7cd1b 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 2b5eec1f5..fbc0b5abd 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 abc6a14ca..f0c83e334 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 7d257b229..7031112a7 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 2dab4d9e0..bfcf4176a 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 66e6553f2..21f2ac720 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 e84ac3fcf..4aced673d 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 099a64989..ebf3061e5 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 07aa627a6..83a0023e3 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 a6bb5f8c8..c00e58316 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 d5f2ba0ba..9df91998e 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 552054287..4325cc2b3 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 edb59f920..90ea71ec2 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 1981b5831..3eff57c67 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 ea2185a38..4f7901250 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 20a199080..fd42a7315 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 edf0a96b0..7c08b85b5 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 da056556b..7faba5769 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 c6da39024..de1c42562 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 d99bd8185..4a808ec9f 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 6d939fff8..a8b073e6a 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 82f0d92a7..8fa6e3738 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 bc5bcd8bd..33f82a426 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 6651ef5c2..d527baa7b 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 554b4ef7f..fb0562f94 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 0e40ced21..01e18cf09 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 2e8ac2663..7ff53b09e 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 f7a4e19c1..0ee9c2972 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 1e89163f1..5d7e311dd 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 3f6c8d174..196c6f186 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 7ba083b80..541b57a74 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 c901be79d..138e444ce 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 73642d28c..910bc957f 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 7432d4c0e..a767b3a1f 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 69a2ffa0b..5aae6a06d 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 d27dd7eb3..87e67b06e 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 fb68b01ed..1fd8dc853 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 11f599d00..1eba42cd0 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 ff585d094..07a35c907 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 bca5b593c..604a1f10b 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 dfb676620..d4f268487 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 ebfa9fd98..413fed633 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 fb887132b..1e39f1010 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 d820bb894..959fa506c 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 19616941b..8868c32a3 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 9213c8d4f..ab03f21a3 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 587b96384..9828f8b22 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 3ff476bb8..d2037b440 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 2a7a30601..b103a70ef 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 f1f7a0306..dfcf26e43 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 39b9ae673..d67b87ab1 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 d65e81e46..7a0d9a3dc 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 b40b2001d..62aa68e8c 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 7c51de497..e478c9c3c 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 89fda438c..512bb167b 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 8a58f81a2..faa2928bc 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 d7b74dd0c..3ff3ecacd 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 0d1843328..1fba2c5f1 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 2755d0e11..ef1da5115 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 fc288e80e..c38a880d9 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 2b3b6d902..e76eb65c7 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 b688574fb..a51d107b8 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 05e084c88..c475a9d98 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 e82c65c5c..34db6f619 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 e783c2bca..42bdb8da9 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 d5c599239..b03d32691 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 45c6b6d6e..e3ff42774 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 50e232db4..91e4df41c 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 8fcddb6cf..7697f48e6 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 583670f50..29fffef21 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 6d6fc9ca4..3e6dec51d 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 e45a39db2..bed84da89 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 8df20af82..931748cc9 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 eab65196a..bb56d790d 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 858e8d7d1..cddcf921f 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 e4ea14350..937a11bce 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 d851b1e51..a3f965f93 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 96fdff492..c47f26f34 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 370c3d29b..9f11e9f08 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 c02a649e0..dd391a803 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 035565377..2b74a010e 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 52d25f1fc..62759f6f9 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 ab6365d8f..b4ee49ea9 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 0364def9a..dd17f5c21 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 ce8dbae0f..276abf656 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 f29e5b53f..b308ffd62 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 4b13266a6..33c66f820 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 3219828be..0428668b0 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 51371cca4..d4f3653ef 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 dc56df944..24e6400a6 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() - } } -- GitLab