diff --git a/CHANGELOG b/CHANGELOG
index 6b18b48..55ff374 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,7 @@ External contributors notice at the end of the line: (LastName, FirstName / nick
## 2022-10-15 2.2.0
Add SOLO functionality alongside the existing audible/mute layer. Control via shortcuts, track editor, or track list widget
+New function to create a new empty block from an existing one, that has reserved duration same as the original one.
Add more time signatures to the quick-insert dialog: 8/4, three variants of 7/8, two variants of 5/4 and more. Also reorder and better labels.
Fix splitting of notes that were created by a previous split.
Block Mode: Fix invisible block labels and graphics when dragging blocks (adopting to unannounced Qt regressions once again)
diff --git a/engine/api.py b/engine/api.py
index 1cb9b53..0c74710 100644
--- a/engine/api.py
+++ b/engine/api.py
@@ -965,7 +965,7 @@ def duplicateBlock(blockId, times = 1):
callbacks._updateTrack(id(track))
#callbacks._setCursor()
-def duplicateContentLinkBlock(blockId, times = 1):
+def duplicateContentLinkBlock(blockId, times=1):
track, block = session.data.blockById(blockId)
session.history.register(lambda i=id(track), l=track.asListOfBlockIds(): rearrangeBlocks(i, l), descriptionString = "content link block")
for i in range(times):
@@ -973,6 +973,23 @@ def duplicateContentLinkBlock(blockId, times = 1):
callbacks._updateTrack(id(track))
#callbacks._setCursor() #this will make the GUI jump around because it centers on the cursor
+def duplicateToReservedSpaceBlock(blockId, times=1):
+ """Create a new block that has the same duration as the given one.
+ The duration will be reserved.
+ Intended for the composition phase.
+ For example used to create a template for a second voice, where the total duration
+ is already known and can be reserved, so the following blocks are in the right place."""
+ track, block = session.data.blockById(blockId)
+ session.history.register(lambda i=id(track), l=track.asListOfBlockIds(): rearrangeBlocks(i, l), descriptionString = "duplicate block as reserved space")
+ for i in range(times):
+ track.duplicateToReservedSpaceBlock(block)
+ callbacks._updateTrack(id(track))
+
+def duplicateToReservedSpaceCurrentBlock():
+ currentBlockId = id(session.data.currentTrack().currentBlock())
+ duplicateToReservedSpaceBlock(currentBlockId, 1) #handles callbacks and undo
+
+
def moveBlockToOtherTrack(blockId, newTrackId, listOfBlockIdsForNewTrack):
"""First move the block to the new track and then
rearrange both tracks
@@ -1106,15 +1123,6 @@ def moveCurrentBlockToStartOfTrack():
moveBlockToStartOfTrack(id(session.data.currentTrack().currentBlock()))
-#deprecated
-def _setBlockData(block, newData):
- """DEPRECATED. This did not work. The linked blocks were not reduced.
- At point of the bug reports, instead of fixing this, we used
- duplicate block and delete which already provides all functionality"""
- session.history.register(lambda bl=block, old=block.data: _setBlockData(bl, old), descriptionString = "set block data")
- block.data = newData
- #no callbacks needed.
-
#Cursor
def getCursorPitch():
diff --git a/engine/block.py b/engine/block.py
index 84af06e..ff1ad8b 100644
--- a/engine/block.py
+++ b/engine/block.py
@@ -151,7 +151,7 @@ class Block(object):
else:
self._parentTrack = None
- def copy(self, newParentTrack):
+ def copy(self, newParentTrack, nameSuffix="-copy"):
"""Return an independet copy of this block.
It will not be inserted into a track here but in the parentTrack
@@ -174,10 +174,10 @@ class Block(object):
if self in copyItem.parentBlocks: #TODO: investigate
copyItem.parentBlocks.remove(self)
- if self.name.endswith("-copy"): #name is mutable, but getter and setter deal with that.
+ if self.name.endswith(nameSuffix): #name is mutable, but getter and setter deal with that.
new.name = self.name
else:
- new.name = self.name + "-copy"
+ new.name = self.name + nameSuffix
new._minimumInTicks = self._minimumInTicks[:] #it is a mutable value, we make a copy of the list (which has an int inside, which is immutable and copied automatically)
return new
diff --git a/engine/track.py b/engine/track.py
index 26a9137..5df38b4 100644
--- a/engine/track.py
+++ b/engine/track.py
@@ -481,6 +481,20 @@ class Track(object):
self.blocks.insert(index +1, linked)
self.toPosition(originalPosition) #has head() in it
+ def duplicateToReservedSpaceBlock(self, block):
+ """We actually do a copy and then remove the content.
+ While at the moment of creation (v2.2.0) it would be equally well to create a new empty
+ block and set the duration and name this way is better for future functionality."""
+ originalPosition = self.state.position()
+ index = self.blocks.index(block)
+ copy = block.copy(newParentTrack=self, nameSuffix="-reserved")
+
+ copy.data = list() #empty
+ copy.minimumInTicks = self.duration()
+
+ self.blocks.insert(index +1, copy)
+ self.toPosition(originalPosition) #has head() in it
+
def hasContentLinks(self):
return any(len(block.linkedContentBlocks) > 1 for block in self.blocks)
diff --git a/qtgui/designer/mainwindow.py b/qtgui/designer/mainwindow.py
index cf59bbb..50495b1 100644
--- a/qtgui/designer/mainwindow.py
+++ b/qtgui/designer/mainwindow.py
@@ -697,6 +697,8 @@ class Ui_MainWindow(object):
self.actionToggle_Track_Solo_Playback.setObjectName("actionToggle_Track_Solo_Playback")
self.actionReset_all_Solo = QtWidgets.QAction(MainWindow)
self.actionReset_all_Solo.setObjectName("actionReset_all_Solo")
+ self.actionCreate_reserved_duration_empty_block_from_current = QtWidgets.QAction(MainWindow)
+ self.actionCreate_reserved_duration_empty_block_from_current.setObjectName("actionCreate_reserved_duration_empty_block_from_current")
self.menuObjects.addAction(self.actionMetrical_Instruction)
self.menuObjects.addAction(self.actionCustom_Metrical_Instruction)
self.menuObjects.addAction(self.actionClef)
@@ -789,6 +791,7 @@ class Ui_MainWindow(object):
self.menuTracks.addAction(self.actionSplit_Current_Block)
self.menuTracks.addAction(self.actionAppend_Block)
self.menuTracks.addAction(self.actionDuplicate)
+ self.menuTracks.addAction(self.actionCreate_reserved_duration_empty_block_from_current)
self.menuTracks.addAction(self.actionUnlink_Current_Block)
self.menuTracks.addAction(self.actionCreate_Linked_Copy)
self.menuTracks.addAction(self.actionDelete_Current_Block)
@@ -1068,3 +1071,4 @@ class Ui_MainWindow(object):
self.actionToggle_Track_Solo_Playback.setText(_translate("MainWindow", "Toggle Track Solo Playback"))
self.actionToggle_Track_Solo_Playback.setShortcut(_translate("MainWindow", "Z"))
self.actionReset_all_Solo.setText(_translate("MainWindow", "Reset Solo for all Tracks"))
+ self.actionCreate_reserved_duration_empty_block_from_current.setText(_translate("MainWindow", "Create reserved-duration empty block from current"))
diff --git a/qtgui/designer/mainwindow.ui b/qtgui/designer/mainwindow.ui
index e0012dd..654c62a 100644
--- a/qtgui/designer/mainwindow.ui
+++ b/qtgui/designer/mainwindow.ui
@@ -168,6 +168,7 @@
+
@@ -1876,6 +1877,11 @@
Reset Solo for all Tracks
+
+
+ Create reserved-duration empty block from current
+
+
diff --git a/qtgui/menu.py b/qtgui/menu.py
index 9ce8037..97e7651 100644
--- a/qtgui/menu.py
+++ b/qtgui/menu.py
@@ -277,6 +277,7 @@ class MenuActionDatabase(object):
self.mainWindow.ui.actionSplit_Current_Block : api.splitBlock,
self.mainWindow.ui.actionJoin_with_next_Block : api.joinBlock,
self.mainWindow.ui.actionDuplicate : api.duplicateCurrentBlock,
+ self.mainWindow.ui.actionCreate_reserved_duration_empty_block_from_current : api.duplicateToReservedSpaceCurrentBlock,
self.mainWindow.ui.actionCreate_Linked_Copy : api.duplicateContentLinkCurrentBlock,
self.mainWindow.ui.actionUnlink_Current_Block : api.unlinkCurrentBlock,
self.mainWindow.ui.actionDelete_Current_Block : api.deleteCurrentBlock,
diff --git a/qtgui/musicstructures.py b/qtgui/musicstructures.py
index f63794d..c3d647a 100644
--- a/qtgui/musicstructures.py
+++ b/qtgui/musicstructures.py
@@ -175,6 +175,7 @@ class GuiBlockHandle(QtWidgets.QGraphicsRectItem):
("separator", None),
#("split here", lambda: self.splitHere(event)), #Impossible because we can't see notes.
(translate("musicstructures", "duplicate"), lambda: api.duplicateBlock(self.staticExportItem["id"])),
+ (translate("musicstructures", "duplicate to reserved empty"), lambda: api.duplicateToReservedSpaceBlock(self.staticExportItem["id"])),
(translate("musicstructures", "create content link"), lambda: api.duplicateContentLinkBlock(self.staticExportItem["id"])),
(translate("musicstructures", "unlink"), lambda: api.unlinkBlock(self.staticExportItem["id"])),
(translate("musicstructures", "move to start"), lambda: api.moveBlockToStartOfTrack(self.staticExportItem["id"])),