1 Commits

Author SHA1 Message Date
c7e057b727 [feat] remove format string & preview from GUI
Personal opinion: being able to change the format in the GUI,
 but not the fingering, felt misleading.
 I think the user should either be directed to the Fingering.js file
 or we should have a complete editor of fingerings in the GUI.
Since adding more elements to the GUI would be a lot of work,
 I opted for the first option.

- Removed all references to the format string and preview window
- Also fixed some wordings/indentation
2026-05-16 15:47:23 +02:00

View File

@ -102,20 +102,11 @@ MuseScore {
return profiles.length > 0 ? profiles[currentProfileIndex].format : ""
}
function setCurrentFormatString(newFormat) {
if (profiles.length > 0) {
profiles[currentProfileIndex].format = newFormat
userFormatString = newFormat
}
}
Settings {
id: pluginSettings
category: "whistleTab"
// Declare each setting as a property (with defaults)
property string storedProfiles: ""
property int storedCurrentProfile: 0
property int storedFontSize: 8
property int storedJustification: 1
@ -143,11 +134,9 @@ MuseScore {
offsetField.text = userOffsetY.toFixed(1)
spacingField.text = userLineSpacing.toFixed(1)
justCombo.currentIndex = userJustification
formatInput.text = userFormatString
transposedCheck.checked = userTransposed
profileCombo.currentIndex = currentProfileIndex
updatePreview()
}
//---------------------------------------------------------
@ -166,13 +155,6 @@ MuseScore {
//---------------------------------------------------------
function saveSettings() {
// Save profiles as JSON string
var profilesForStorage = profiles.map(p => ({
name: p.name,
fingering: p.fingering,
format: p.format
}))
pluginSettings.storedProfiles = JSON.stringify(profilesForStorage)
pluginSettings.storedCurrentProfile = currentProfileIndex
pluginSettings.storedFontSize = userFontSize
pluginSettings.storedJustification = userJustification
@ -186,51 +168,30 @@ MuseScore {
function loadSettings() {
// Load profiles
var profilesStr = pluginSettings.storedProfiles
if (profilesStr && profilesStr !== "") {
try {
var loaded = JSON.parse(profilesStr)
profiles = loaded.map(p => ({
name: p.name,
fingering: p.fingering,
format: p.format
}))
} catch (e) {
console.log("Failed to parse saved profiles, using defaults")
error("Failed to parse saved profiles, using defaults")
profiles = Fingering.woodwinds.map(p => ({
name: p.name,
fingering: JSON.parse(JSON.stringify(p.fingering)),
format: p.format
}))
}
} else {
profiles = Fingering.woodwinds.map(p => ({
name: p.name,
fingering: JSON.parse(JSON.stringify(p.fingering)),
format: p.format
}))
}
profiles = Fingering.woodwinds.map(p => ({
name: p.name,
fingering: JSON.parse(JSON.stringify(p.fingering)),
format: p.format
}))
// Load current profile index
currentProfileIndex = pluginSettings.storedCurrentProfile
if (currentProfileIndex < 0 || currentProfileIndex >= profiles.length)
currentProfileIndex = 0
// Load global settings (fall back to defaults if stored value is undefined)
userFontSize = pluginSettings.storedFontSize ?? defaultFontSize
userJustification = pluginSettings.storedJustification ?? defaultJustification
userOffsetY = pluginSettings.storedOffsetY ?? defaultOffsetY
userLineSpacing = pluginSettings.storedLineSpacing ?? defaultLineSpacing
userFontFamily = pluginSettings.storedFontFamily ?? defaultFontFamily
userTransposed = pluginSettings.storedTransposed ?? defaultTransposed
// Load global settings (fall back to defaults if stored value is undefined)
userFontSize = pluginSettings.storedFontSize ?? defaultFontSize
userJustification = pluginSettings.storedJustification ?? defaultJustification
userOffsetY = pluginSettings.storedOffsetY ?? defaultOffsetY
userLineSpacing = pluginSettings.storedLineSpacing ?? defaultLineSpacing
userFontFamily = pluginSettings.storedFontFamily ?? defaultFontFamily
userTransposed = pluginSettings.storedTransposed ?? defaultTransposed
if (typeof fontFamilyField !== 'undefined') {
fontFamilyField.text = userFontFamily
}
if (typeof fontFamilyField !== 'undefined') {
fontFamilyField.text = userFontFamily
}
console.log("Settings loaded")
console.log("Settings loaded")
}
//---------------------------------------------------------
// Reset to defaults
@ -240,11 +201,6 @@ MuseScore {
getHistory().begin() // if you have undo/redo
// 1. Restore profiles from woodwinds
profiles = Fingering.woodwinds.map(p => ({
name: p.name,
fingering: JSON.parse(JSON.stringify(p.fingering)),
format: p.format
}))
currentProfileIndex = 0
// 2. Reset global settings to defaults
@ -257,34 +213,27 @@ MuseScore {
// 3. Update UI to reflect the new profile and settings
userFormatString = getCurrentFormatString()
formatInput.text = userFormatString
profileCombo.currentIndex = 0
fontSizeField.text = userFontSize
fontFamilyField.text = userFontFamily
offsetField.text = userOffsetY.toFixed(1)
spacingField.text = userLineSpacing.toFixed(1)
justCombo.currentIndex = userJustification
transposedCheck.checked = userTransposed
profileCombo.currentIndex = 0
fontSizeField.text = userFontSize
fontFamilyField.text = userFontFamily
offsetField.text = userOffsetY.toFixed(1)
spacingField.text = userLineSpacing.toFixed(1)
justCombo.currentIndex = userJustification
transposedCheck.checked = userTransposed
// 4. Persist all changes to Settings
pluginSettings.storedProfiles = JSON.stringify(profiles.map(p => ({
name: p.name,
fingering: p.fingering,
format: p.format
})))
pluginSettings.storedCurrentProfile = currentProfileIndex
pluginSettings.storedFontSize = userFontSize
pluginSettings.storedJustification = userJustification
pluginSettings.storedOffsetY = userOffsetY
pluginSettings.storedLineSpacing = userLineSpacing
pluginSettings.storedFontFamily = userFontFamily
pluginSettings.storedTransposed = userTransposed
pluginSettings.sync() // optional: force immediate write
// 4. Persist all changes to Settings
pluginSettings.storedCurrentProfile = currentProfileIndex
pluginSettings.storedFontSize = userFontSize
pluginSettings.storedJustification = userJustification
pluginSettings.storedOffsetY = userOffsetY
pluginSettings.storedLineSpacing = userLineSpacing
pluginSettings.storedFontFamily = userFontFamily
pluginSettings.storedTransposed = userTransposed
pluginSettings.sync() // optional: force immediate write
getHistory().end()
updatePreview()
console.log("Reset to defaults")
getHistory().end()
console.log("Reset to defaults")
}
//---------------------------------------------------------
@ -429,7 +378,7 @@ MuseScore {
const half_hor = "-"
const open_split = "o"
if (!binaryString || binaryString.length < 1)
return "Invalid fingering pattern. Length is wrong"
return "Invalid fingering pattern. Length is wrong. Check Fingering.js"
if (!format || typeof format !== "string")
return "ERR"
@ -446,7 +395,7 @@ MuseScore {
binaryString[i] !== half_ver &&
binaryString[i] !== half_hor &&
binaryString[i] !== open_split)
return "Invalid Fingering Pattern Value. Check the config in the .qml file!"
return "Invalid Fingering Pattern Value. Check Fingering.js"
}
//-------------------------------------------------
@ -714,52 +663,12 @@ MuseScore {
return notes[randomIndex]
}
function getPreviewText() {
var dict = getCurrentFingeringDict()
var firstNote = getRandomNoteName()
if (dict[firstNote]) {
return buildFingeringText(dict[firstNote], formatInput.text, firstNote)
}
return "No preview available"
}
//Estimate offset for preview font size to match what will appear on staff at 100% zoom
function computePreviewOffset() {
var dpiScale = 96 / 72 // MuseScore vs Qt DPI convention
return Math.round(userFontSize * Screen.devicePixelRatio * dpiScale) - userFontSize
}
//Font definition for preview symbols. Does not support multiple fonts, so only use the whistle font
function getPreviewFont(){
var baseFont = Qt.font({
family: "WhistleSymbols",
pointSize: Math.max(1, userFontSize + computePreviewOffset()) //offset font size to match visual size on staff
})
// Split userFontFamily string into array and flatten with whistle font
var fallbacks = userFontFamily.split(',').map(f => f.trim())
baseFont.families = ["WhistleSymbols"].concat(fallbacks)
return baseFont
}
// Build the full font stack dynamically
function getFontStack() {
// return "WhistleSymbols" + ", " + userFontFamily;
return userFontFamily
}
function updatePreview() {
//Replace whitespaces with non-breaking whitespace, as the label field ignores
//whitespaces when justifying, making the preview inaccurate otherwise.
previewLabel.text = getPreviewText().replace(/ /g, "\u00A0")
}
//---------------------------------------------------------
// Setters with undo/redo
//---------------------------------------------------------
@ -770,12 +679,10 @@ MuseScore {
function() {
userFontSize = oldSize
fontSizeField.text = oldSize
previewLabel.font.pointSize = Math.max(1, oldSize + computePreviewOffset())
},
function() {
userFontSize = size
fontSizeField.text = size
previewLabel.font.pointSize = Math.max(1, size + computePreviewOffset())
},
"font size"
)
@ -786,12 +693,10 @@ MuseScore {
function() {
userFontFamily = oldFamily
fontFamilyField.text = oldFamily
previewLabel.font = getPreviewFont()
},
function() {
userFontFamily = family
fontFamilyField.text = family
previewLabel.font = getPreviewFont()
},
"font family"
)
@ -836,30 +741,6 @@ MuseScore {
)
}
function setUserFormatString(format) {
var oldFormat = userFormatString
var oldProfileFormat = getCurrentFormatString()
getHistory().add(
function() {
// Undo: restore both userFormatString and the profile's format
userFormatString = oldFormat
formatInput.text = oldFormat
if (profiles.length > 0) {
profiles[currentProfileIndex].format = oldProfileFormat
}
},
function() {
// Redo: apply new format to both
userFormatString = format
formatInput.text = format
if (profiles.length > 0) {
profiles[currentProfileIndex].format = format
}
},
"format string"
)
}
function setModified(state) {
var oldModified = modified
getHistory().add(
@ -873,19 +754,10 @@ MuseScore {
// Event handlers (call setters and save)
//---------------------------------------------------------
function formatChanged(format) {
getHistory().begin()
setModified(true)
setUserFormatString(format)
getHistory().end()
saveSettings()
}
function fontSizeChanged(size) {
getHistory().begin()
setModified(true)
setUserFontSize(size)
updatePreview()
getHistory().end()
saveSettings()
}
@ -894,7 +766,6 @@ MuseScore {
getHistory().begin()
setModified(true)
setUserFontFamily(family)
updatePreview()
getHistory().end()
saveSettings()
}
@ -904,7 +775,6 @@ MuseScore {
getHistory().begin()
setModified(true)
setUserJustification(justification)
updatePreview()
getHistory().end()
saveSettings()
}
@ -913,7 +783,6 @@ MuseScore {
getHistory().begin()
setModified(true)
setUserOffsetY(offset)
updatePreview()
getHistory().end()
saveSettings()
}
@ -922,7 +791,6 @@ MuseScore {
getHistory().begin()
setModified(true)
setUserLineSpacing(spacing)
updatePreview()
getHistory().end()
saveSettings()
}
@ -931,8 +799,6 @@ MuseScore {
if (index < 0 || index >= profiles.length) return
currentProfileIndex = index
userFormatString = profiles[index].format
formatInput.text = userFormatString
updatePreview()
saveSettings() // immediately save profile change
}
@ -1074,13 +940,6 @@ MuseScore {
}
}
}
onTextChanged: {
var newValue = parseInt(text)
if (!isNaN(newValue) && newValue >= 1 && newValue <= 999) {
previewLabel.font.pointSize = Math.max(1, newValue + computePreviewOffset())
}
}
}
Label {
@ -1095,7 +954,6 @@ MuseScore {
currentIndex: userJustification
onActivated: {
justificationChanged(index)
updatePreview()
}
contentItem: Text {
text: justCombo.displayText
@ -1134,7 +992,6 @@ MuseScore {
if (!isNaN(newValue) && newValue >= -999.0 && newValue <= 999.0) {
if (newValue !== userOffsetY) {
offsetYChanged(newValue)
updatePreview()
}
} else {
text = userOffsetY.toFixed(1)
@ -1147,7 +1004,6 @@ MuseScore {
if (!isNaN(newValue) && newValue >= -999.0 && newValue <= 999.0) {
if (newValue !== userOffsetY) {
offsetYChanged(newValue)
updatePreview()
}
} else {
text = userOffsetY.toFixed(1)
@ -1209,7 +1065,6 @@ MuseScore {
if (!isNaN(newValue) && newValue >= 0 && newValue <= 6) {
if (newValue !== userLineSpacing) {
lineSpacingChanged(newValue)
updatePreview()
}
} else {
text = userLineSpacing.toFixed(1)
@ -1222,7 +1077,6 @@ MuseScore {
if (!isNaN(newValue) && newValue >= 0 && newValue <= 999) {
if (newValue !== userLineSpacing) {
lineSpacingChanged(newValue)
updatePreview()
}
} else {
text = userLineSpacing.toFixed(1)
@ -1303,130 +1157,6 @@ MuseScore {
}
}
// BOTTOM ROW - Format String and Preview
GroupBox {
title: "Format String & Preview"
Layout.fillWidth: true
Layout.columnSpan: 2
background: Rectangle {
color: backgroundColor
border.color: textColor
}
label: Label {
text: parent.title
color: textColor
background: Rectangle { color: backgroundColor }
}
RowLayout {
width: parent.width
spacing: 20
anchors.margins: 10
// Format String Area (left side)
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 5
Label {
text: "Format String:"
color: textColor
font.bold: true
}
ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredHeight: 200
clip: true
background: Rectangle {
color: backgroundColor
border.color: textColor
}
TextArea {
id: formatInput
width: parent.width
height: contentHeight
wrapMode: TextEdit.Wrap
text: userFormatString
color: sysPal.text
selectionColor: sysPal.highlight
selectedTextColor: sysPal.highlightedText
background: Rectangle {
color: backgroundColor
border.color: textColor
}
property var previousText: userFormatString
onEditingFinished: {
formatChanged(formatInput.text)
updatePreview()
}
onTextChanged: {
updatePreview()
}
}
}
Label {
text: "Use placeholders like $1, $2, ..., for the holes and $note for the note (e.g. G#5)"
font.pixelSize: 10
color: textColor
}
}
// Preview Area (right side)
GroupBox {
title: "Preview (@100%)"
Layout.preferredWidth: 120
Layout.fillHeight: true
background: Rectangle {
color: backgroundColor
border.color: textColor
}
label: Label {
text: parent.title
color: textColor
background: Rectangle { color: backgroundColor }
}
ScrollView {
anchors.fill: parent
anchors.margins: 5
clip: true
background: Rectangle {
color: backgroundColor
border.color: textColor
}
Label {
id: previewLabel
text: getPreviewText()
ToolTip.visible: hovered
ToolTip.delay: 1000
ToolTip.text: "Due to a limitation, the preview font does not reflect the selected font"
//font.family: getFontStack()
//font.pointSize: userFontSize
color: textColor
wrapMode: Text.NoWrap
width: parent.width
lineHeight: userLineSpacing
lineHeightMode: Text.ProportionalHeight
font: getPreviewFont()
// Dynamic alignment based on userJustification
horizontalAlignment: {
if (userJustification === 0) return Text.AlignLeft
if (userJustification === 1) return Text.AlignHCenter
return Text.AlignRight
}
}
}
}
}
}
// BOTTOM BUTTONS - Apply and Cancel
RowLayout {
Layout.columnSpan: 2
@ -1519,7 +1249,7 @@ MuseScore {
MessageDialog {
id: resetDialog
title: "Confirm"
text: "This will refresh and reset all text configurations, woodwind dictionaries and format strings. Continue?"
text: "This will refresh and reset all text configurations. Continue?"
standardButtons: [StandardButton.Ok, StandardButton.Cancel]
onAccepted: {
resetToDefaults()