Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Percussion panel - implement keyboard navigation for toolbar and pad grid #25518

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 133 additions & 25 deletions src/notation/qml/MuseScore/NotationScene/PercussionPanel.qml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ Item {
Component.onCompleted: {
percModel.init()
}

onCurrentPanelModeChanged: {
// Cancel any active keyboard swaps when the panel mode changes
if (padGrid.isKeyboardSwapActive) {
padGrid.swapOriginPad = null
padGrid.isKeyboardSwapActive = false
padGrid.model.endPadSwap(-1)
}
}
}

// TODO: Will live inside percussion panel until #22050 is implemented
Expand All @@ -69,8 +78,8 @@ Item {
width: parent.width
height: 36

navigation.section: root.navigationSection
navigation.order: root.contentNavigationPanelOrderStart
navigationSection: root.navigationSection
navigationOrderStart: root.contentNavigationPanelOrderStart

model: percModel

Expand Down Expand Up @@ -103,6 +112,16 @@ Item {
height: padGrid.cellHeight * padGrid.numRows
spacing: padGrid.spacing / 2

NavigationPanel {
id: deleteButtonsPanel

name: "PercussionPanelDeleteRowButtons"
section: root.navigationSection
order: toolbar.navigationOrderEnd + 3

enabled: deleteButtonsColumn.visible
}

Column {
id: deleteButtonsColumn

Expand All @@ -112,6 +131,7 @@ Item {
width: rowLayout.sideColumnsWidth

visible: percModel.currentPanelMode === PanelMode.EDIT_LAYOUT
enabled: !padGrid.isKeyboardSwapActive

Repeater {
id: deleteRepeater
Expand All @@ -135,6 +155,9 @@ Item {
icon: IconCode.DELETE_TANK
backgroundRadius: deleteButton.width / 2

navigation.panel: deleteButtonsPanel
navigation.row: model.index

onClicked: {
padGrid.model.deleteRow(model.index)
}
Expand All @@ -161,7 +184,16 @@ Item {
readonly property int numColumns: model.numColumns
readonly property int spacing: 12

property Item draggedPad: null
property Item swapOriginPad: null
property bool isKeyboardSwapActive: false

QtObject {
id: gridPrv

// This variable ensures we stay within a given pad when tabbing back-and-forth between
// "main" and "footer" controls
property var currentPadNavigationIndex: [0, 0]
}

Layout.alignment: Qt.AlignTop
Layout.fillHeight: true
Expand All @@ -175,6 +207,36 @@ Item {

model: percModel.padListModel

NavigationPanel {
id: padsNavPanel

name: "PercussionPanelPads"
section: root.navigationSection
order: toolbar.navigationOrderEnd + 1

onNavigationEvent: function(event) {
if (event.type === NavigationEvent.AboutActive) {
event.setData("controlIndex", gridPrv.currentPadNavigationIndex)
}
}
}

NavigationPanel {
id: padFootersNavPanel

name: "PercussionPanelFooters"
section: root.navigationSection
order: toolbar.navigationOrderEnd + 2

enabled: percModel.currentPanelMode !== PanelMode.EDIT_LAYOUT

onNavigationEvent: function(event) {
if (event.type === NavigationEvent.AboutActive) {
event.setData("controlIndex", gridPrv.currentPadNavigationIndex)
}
}
}

delegate: Item {
id: padArea

Expand All @@ -194,54 +256,96 @@ Item {
panelMode: percModel.currentPanelMode
useNotationPreview: percModel.useNotationPreview

// When dragging, only show the outline for the dragged pad and the drag target...
// When swapping, only show the outline for the swap origin and the swap target...
showEditOutline: percModel.currentPanelMode === PanelMode.EDIT_LAYOUT
&& (!Boolean(padGrid.draggedPad) || padGrid.draggedPad === pad || pad.containsDrag)
showOriginBackground: pad.containsDrag || pad === padGrid.draggedPad
&& (!Boolean(padGrid.swapOriginPad) || padGrid.swapOriginPad === pad)
showOriginBackground: pad.containsDrag || (pad === padGrid.swapOriginPad && !padGrid.isKeyboardSwapActive)

panelHasActiveKeyboardSwap: padGrid.isKeyboardSwapActive
dragParent: root

onDragStarted: {
padGrid.draggedPad = pad
padGrid.model.startDrag(index)
navigationRow: index / padGrid.numColumns
navigationColumn: index % padGrid.numColumns
padNavigation.panel: padsNavPanel
footerNavigation.panel: padFootersNavPanel

onStartPadSwapRequested: function(isKeyboardSwap) {
padGrid.swapOriginPad = pad
padGrid.isKeyboardSwapActive = isKeyboardSwap
padGrid.model.startPadSwap(index)
}

onDropped: function(dropEvent) {
padGrid.draggedPad = null
padGrid.model.endDrag(index)
dropEvent.accepted = true
onEndPadSwapRequested: {
padGrid.swapOriginPad = null
padGrid.isKeyboardSwapActive = false
padGrid.model.endPadSwap(index)
}

onDragCancelled: {
padGrid.draggedPad = null
padGrid.model.endDrag(-1)
onCancelPadSwapRequested: {
padGrid.swapOriginPad = null
padGrid.isKeyboardSwapActive = false
padGrid.model.endPadSwap(-1)
}

onHasActiveControlChanged: {
if (!pad.hasActiveControl) {
return;
}
gridPrv.currentPadNavigationIndex = [pad.navigationRow, pad.navigationColumn]
}
}

states: [
// If this is the drop target - move the draggable area to the origin of the dragged pad (preview the drop)
// If this is the swap target - move the swappable area to the swap origin (preview the swap)
State {
name: "DROP_TARGET"
when: Boolean(padGrid.draggedPad) && pad.containsDrag && padGrid.draggedPad !== pad
name: "SWAP_TARGET"
when: Boolean(padGrid.swapOriginPad) && (pad.containsDrag || pad.padNavigationCtrl.active) && padGrid.swapOriginPad !== pad

ParentChange {
target: pad.draggableArea
parent: padGrid.draggedPad
target: pad.swappableArea
parent: padGrid.swapOriginPad
}
AnchorChanges {
target: pad.draggableArea
anchors.verticalCenter: padGrid.draggedPad.verticalCenter
anchors.horizontalCenter: padGrid.draggedPad.horizontalCenter
target: pad.swappableArea
anchors.verticalCenter: padGrid.swapOriginPad.verticalCenter
anchors.horizontalCenter: padGrid.swapOriginPad.horizontalCenter
}
PropertyChanges {
target: pad
showEditOutline: true
}

// Origin background not needed for the dragged pad when a preview is taking place...
PropertyChanges {
target: padGrid.draggedPad
target: padGrid.swapOriginPad
showOriginBackground: false
}

// In the case of a keyboard swap, we also need to move the origin pad
ParentChange {
target: padGrid.isKeyboardSwapActive && Boolean(padGrid.swapOriginPad) ? padGrid.swapOriginPad.swappableArea : null
parent: pad
}
AnchorChanges {
target: padGrid.isKeyboardSwapActive && Boolean(padGrid.swapOriginPad) ? padGrid.swapOriginPad.swappableArea : null
anchors.verticalCenter: pad.verticalCenter
anchors.horizontalCenter: pad.horizontalCenter
}
}
]
}
}

NavigationPanel {
id: addRowButtonPanel

name: "PercussionPanelAddRowButton"
section: root.navigationSection
order: toolbar.navigationOrderEnd + 4

enabled: addRowButton.visible
}

FlatButton {
id: addRowButton

Expand All @@ -250,10 +354,14 @@ Item {
Layout.bottomMargin: (padGrid.cellHeight / 2) - (height / 2)

visible: percModel.currentPanelMode === PanelMode.EDIT_LAYOUT
enabled: !padGrid.isKeyboardSwapActive

icon: IconCode.PLUS
text: qsTrc("notation", "Add row")
orientation: Qt.Horizontal

navigation.panel: addRowButtonPanel

onClicked: {
padGrid.model.addEmptyRow()
flickable.goToBottom()
Expand Down
Loading