diff --git a/engine/api.py b/engine/api.py
index 09ab24b..ef9c53a 100644
--- a/engine/api.py
+++ b/engine/api.py
@@ -2494,12 +2494,32 @@ def midiRelativeChannelReset():
#Lilypond
-def lilypondText(text):
+def lilypondText(text:str):
+ """This is the generic lilypond item. It will get inserted as-is"""
try:
insertItem(items.LilypondText(text))
except Exception as err:
logger.error(err)
+def lilypondMark(text:str, aboveStaff=True):
+ """This is actual human-readable text, called a Mark by lilypond.
+ By default is will be above the staff, but it can be below as well.
+
+ It needs to be attached to another item. Lilypond doesn't allow "just place text here".
+
+ https://lilypond.org/doc/v2.23/Documentation/notation/writing-text
+ """
+
+ text = lilypond.lilyfy(text)
+
+ if aboveStaff:
+ text = '^"' + text + '"' #add quotes "" for lilypond
+ else:
+ text = '-"' + text + '"' #add quotes "" for lilypond
+
+ insertItem(items.LilypondText(text))
+
+
def exportLilypond(absoluteFilePath):
save()
lilypond.saveAsLilypond(session.data, absoluteFilePath)
diff --git a/engine/lilypond.py b/engine/lilypond.py
index 6a31771..e581ff1 100644
--- a/engine/lilypond.py
+++ b/engine/lilypond.py
@@ -73,6 +73,13 @@ def stringToCharsOnlyString(string):
return "".join([num2wordForIterations(c) for c in string])
def lilyfy(string):
+ """Escape special lilypond characters like the quote " etc.
+
+ This is extended on a as-needed basis.
+ """
+
+ string = string.replace('"', '\\"')
+
return string
def fromTemplate(session, templateFile, data, meta, tempoStaff):
@@ -102,15 +109,15 @@ def fromTemplate(session, templateFile, data, meta, tempoStaff):
def findTemplate(session, templateFile:str=None)->str:
"""returns a path. checks for existence.
-
+
There are two options:
- Use a standard template in SHARE/lilypondTemplates
- Use a template that belongs to the save file.
-
+
The one that belongs to the save file needs to be created by hand by the user.
If not we throw a FileNotFoundError"""
if templateFile:
- path = os.path.join(PATHS["share"], "lilypondTemplates", templateFile)
+ path = os.path.join(PATHS["share"], "lilypondTemplates", templateFile)
else:
path = os.path.join(session.sessionPrefix, "template.laborejo2.ly") #the name is always the same because the sessionPrefix is the unqiue part
assert path.endswith(".ly")
diff --git a/qtgui/designer/mainwindow.py b/qtgui/designer/mainwindow.py
index 6dddbb5..b63053a 100644
--- a/qtgui/designer/mainwindow.py
+++ b/qtgui/designer/mainwindow.py
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'mainwindow.ui'
#
-# Created by: PyQt5 UI code generator 5.15.2
+# Created by: PyQt5 UI code generator 5.15.6
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
@@ -664,6 +664,10 @@ class Ui_MainWindow(object):
self.actionQuit.setObjectName("actionQuit")
self.actionPlay_from_Block = QtWidgets.QAction(MainWindow)
self.actionPlay_from_Block.setObjectName("actionPlay_from_Block")
+ self.actionLyMarkAbove = QtWidgets.QAction(MainWindow)
+ self.actionLyMarkAbove.setObjectName("actionLyMarkAbove")
+ self.actionLyMarkBelow = QtWidgets.QAction(MainWindow)
+ self.actionLyMarkBelow.setObjectName("actionLyMarkBelow")
self.menuObjects.addAction(self.actionMetrical_Instruction)
self.menuObjects.addAction(self.actionClef)
self.menuObjects.addAction(self.actionKey_Signature)
@@ -847,6 +851,8 @@ class Ui_MainWindow(object):
self.menuLilypond.addAction(self.actionLyBarline)
self.menuLilypond.addAction(self.actionLyRepeat)
self.menuLilypond.addAction(self.actionLyFree_Instruction)
+ self.menuLilypond.addAction(self.actionLyMarkAbove)
+ self.menuLilypond.addAction(self.actionLyMarkBelow)
self.menubar.addAction(self.menuView.menuAction())
self.menubar.addAction(self.menuEdit_2.menuAction())
self.menubar.addAction(self.menu.menuAction())
@@ -986,7 +992,7 @@ class Ui_MainWindow(object):
self.actionRandom_in_scale_in_cursor_plus_octave.setText(_translate("MainWindow", "Random in-scale in cursor plus octave (authentic mode)"))
self.actionRandom_in_scale_in_octave_around_cursor.setText(_translate("MainWindow", "Random in-scale in octave around cursor (hypo mode)"))
self.actionLyBarline.setText(_translate("MainWindow", "Barline"))
- self.actionLyFree_Instruction.setText(_translate("MainWindow", "Free Instruction"))
+ self.actionLyFree_Instruction.setText(_translate("MainWindow", "Free Ly Instruction"))
self.actionLyRepeat.setText(_translate("MainWindow", "Repeat"))
self.actionZoom_In_Score_View.setText(_translate("MainWindow", "Zoom In Score View"))
self.actionZoom_Out_Score_View.setText(_translate("MainWindow", "Zoom Out Score View"))
@@ -994,3 +1000,5 @@ class Ui_MainWindow(object):
self.actionQuit.setShortcut(_translate("MainWindow", "Ctrl+Q"))
self.actionPlay_from_Block.setText(_translate("MainWindow", "Play from Block"))
self.actionPlay_from_Block.setShortcut(_translate("MainWindow", "Alt+Space"))
+ self.actionLyMarkAbove.setText(_translate("MainWindow", "Text above Staff"))
+ self.actionLyMarkBelow.setText(_translate("MainWindow", "Text below Staff"))
diff --git a/qtgui/designer/mainwindow.ui b/qtgui/designer/mainwindow.ui
index 98ebe01..2ec88da 100644
--- a/qtgui/designer/mainwindow.ui
+++ b/qtgui/designer/mainwindow.ui
@@ -323,6 +323,8 @@
+
+
@@ -1711,7 +1713,7 @@
- Free Instruction
+ Free Ly Instruction
@@ -1751,6 +1753,16 @@
Alt+Space
+
+
+ Text above Staff
+
+
+
+
+ Text below Staff
+
+
diff --git a/qtgui/menu.py b/qtgui/menu.py
index 37e7d5f..84d62f9 100644
--- a/qtgui/menu.py
+++ b/qtgui/menu.py
@@ -307,6 +307,8 @@ class MenuActionDatabase(object):
self.mainWindow.ui.actionLyBarline: ChooseOne(self.mainWindow, translate("menu", "Choose a Barline"), api.getLilypondBarlineList()),
self.mainWindow.ui.actionLyRepeat: ChooseOne(self.mainWindow, translate("menu", "Choose a Repeat"), api.getLilypondRepeatList()),
self.mainWindow.ui.actionLyFree_Instruction: lambda: forwardText(self.mainWindow, translate("menu", "Enter Instruction"), api.lilypondText),
+ self.mainWindow.ui.actionLyMarkAbove: lambda: forwardText(self.mainWindow, translate("menu", "Text above the Staff, will be attached to previous(!) item."), lambda tx: api.lilypondMark(tx, True)),
+ self.mainWindow.ui.actionLyMarkBelow: lambda: forwardText(self.mainWindow, translate("menu", "Text below the Staff, will be attached to previous(!) item."), lambda tx: api.lilypondMark(tx, False)),
}
self.modalActions = { #these are only available in Note Edit Mode, not in CC Edit Mode etc.