added key navigation for palette panel

This commit is contained in:
Igor Korsukov 2021-04-09 18:45:39 +02:00
parent b732a3f81a
commit 1b73eed0ae
24 changed files with 493 additions and 665 deletions

View file

@ -158,7 +158,11 @@ DockPage {
Component {
id: keynavComp
KeyNavExample{}
KeyNavExample {
onActiveFocusRequested: {
devtoolsCentral.forceActiveFocus()
}
}
}
}

View file

@ -10,6 +10,8 @@ Rectangle {
property string lastClickedInfo: ""
signal activeFocusRequested()
Rectangle {
id: infoPanel
@ -36,6 +38,13 @@ Rectangle {
sectionName: "mainMenu"
sectionOrder: 101
onActiveChanged: {
if (active) {
root.activeFocusRequested()
root.forceActiveFocus()
}
}
RowLayout {
anchors.fill: parent
spacing: 8

View file

@ -9,6 +9,7 @@ Rectangle {
property alias keynavSection: keynavsec
property alias sectionName: keynavsec.name
property alias sectionOrder: keynavsec.order
property alias active: keynavsec.active
default property alias content: contentItem.data
@ -20,14 +21,8 @@ Rectangle {
onActiveChanged: {
console.debug("KeyNavSection.qml active: " + keynavsec.active)
if (keynavsec.active) {
root.forceActiveFocus()
var p = root.parent
while (p) {
p.focus = true
p = p.parent
}
root.focus = true
}
}
}

View file

@ -133,12 +133,20 @@ DockPage {
}
property KeyNavigationControl keynavTab: KeyNavigationControl {
name: "PanelTab"
name: "PaletteTab"
order: 1 //! TODO Needs order from DockPanel
subsection: notationPage.keynavPanelTabSubSec(palettePanel.area)
onActiveChanged: {
if (active) {
palettePanel.forceActiveFocus()
}
}
}
PalettesWidget {}
PalettesWidget {
anchors.fill: parent
keynavSection: notationPage.keynavPanelSec(palettePanel.area)
}
},
DockPanel {
@ -167,11 +175,17 @@ DockPage {
name: "InstrumentsTab"
order: 2 //! TODO Needs order from DockPanel
subsection: notationPage.keynavPanelTabSubSec(instrumentsPanel.area)
onActiveChanged: {
if (active) {
instrumentsPanel.forceActiveFocus()
}
}
}
InstrumentsPanel {
anchors.fill: parent
keynavSection: notationPage.keynavPanelSec(instrumentsPanel.area)
visible: instrumentsPanel.isShown
}
},
@ -201,6 +215,11 @@ DockPage {
name: "InspectorTab"
order: 3 //! TODO Needs order from DockPanel
subsection: notationPage.keynavPanelTabSubSec(inspectorPanel.area)
onActiveChanged: {
if (active) {
inspectorPanel.forceActiveFocus()
}
}
}
InspectorForm {

View file

@ -81,6 +81,7 @@ DockWindow {
toolbars: [
DockToolBar {
id: mainToolBar
objectName: "mainToolBar"
minimumWidth: 296
minimumHeight: dockWindow.toolbarHeight
@ -96,6 +97,12 @@ DockWindow {
keynav.order: 1
currentUri: dockWindow.currentPageUri
keynav.onActiveChanged: {
if (keynav.active) {
mainToolBar.forceActiveFocus()
}
}
onSelected: {
api.launcher.open(uri)
}
@ -120,6 +127,11 @@ DockWindow {
keynav.section: topToolKeyNavSec
keynav.order: 2
keynav.enabled: notationToolBar.visible
onActiveFocusRequested: {
if (keynav.active) {
notationToolBar.forceActiveFocus()
}
}
Connections {
target: notationToolBar

View file

@ -37,9 +37,17 @@ DockPanel::DockPanel(QQuickItem* parent)
connect(this, &DockPanel::visibleEdited, this, [this](bool visible) {
if (m_dock.panel->isVisible() != visible) {
m_dock.panel->setVisible(visible);
if (!visible) {
m_isShown = false;
}
}
});
connect(m_dock.panel, &QDockWidget::visibilityChanged, this, [this](bool vsbl) {
m_isShown = vsbl;
emit isShownChanged(vsbl);
});
m_eventsWatcher = new EventsWatcher(this);
m_dock.panel->installEventFilter(m_eventsWatcher);
connect(m_eventsWatcher, &EventsWatcher::eventReceived, this, &DockPanel::onWidgetEvent);
@ -58,6 +66,7 @@ void DockPanel::onComponentCompleted()
updateStyle();
m_preferedWidth = width();
m_isShown = panel()->isVisible();
if (minimumWidth() == 0) {
panel()->setMinimumWidth(width());
@ -161,6 +170,11 @@ bool DockPanel::closable() const
return featureEnabled(QDockWidget::DockWidgetClosable);
}
bool DockPanel::isShown() const
{
return m_isShown;
}
bool DockPanel::visible() const
{
return m_dock.panel ? m_dock.panel->isVisible() : false;

View file

@ -36,6 +36,8 @@ class DockPanel : public DockView
Q_PROPERTY(bool floatable READ floatable WRITE setFloatable NOTIFY floatableChanged)
Q_PROPERTY(bool closable READ closable WRITE setClosable NOTIFY closableChanged)
Q_PROPERTY(bool isShown READ isShown NOTIFY isShownChanged)
public:
explicit DockPanel(QQuickItem* parent = nullptr);
~DockPanel() override;
@ -49,6 +51,7 @@ public:
bool floatable() const;
bool closable() const;
bool isShown() const;
bool visible() const override;
struct Widget {
@ -78,6 +81,7 @@ signals:
void floatableChanged(bool floatable);
void closableChanged(bool closable);
void closed();
void isShownChanged(bool isShown);
protected:
void onComponentCompleted() override;
@ -94,6 +98,7 @@ private:
EventsWatcher* m_eventsWatcher = nullptr;
int m_preferedWidth = 0;
bool m_isShown = false;
};
}

View file

@ -42,13 +42,29 @@
<seq>Down</seq>
</SC>
<SC>
<key>nav-trigger</key>
<key>nav-trigger-control</key>
<seq>Return</seq>
</SC>
<SC>
<key>nav-trigger</key>
<key>nav-trigger-control</key>
<seq>Space</seq>
</SC>
<SC>
<key>nav-first-control</key>
<seq>Home</seq>
</SC>
<SC>
<key>nav-last-control</key>
<seq>End</seq>
</SC>
<SC>
<key>nav-nextrow-control</key>
<seq>PgDown</seq>
</SC>
<SC>
<key>nav-prevrow-control</key>
<seq>PgUp</seq>
</SC>
<!-- end Keyboard navigation -->
<SC>

View file

@ -42,13 +42,30 @@
<seq>Down</seq>
</SC>
<SC>
<key>nav-trigger</key>
<key>nav-trigger-control</key>
<seq>Return</seq>
</SC>
<SC>
<key>nav-trigger</key>
<key>nav-trigger-control</key>
<seq>Space</seq>
</SC>
<SC>
<key>nav-first-control</key>
<seq>Home</seq>
</SC>
<SC>
<key>nav-last-control</key>
<seq>End</seq>
</SC>
<SC>
<key>nav-nextrow-control</key>
<seq>PgDown</seq>
</SC>
<SC>
<key>nav-prevrow-control</key>
<seq>PgUp</seq>
</SC>
<!-- end Keyboard navigation -->
<SC>

View file

@ -28,60 +28,6 @@ using namespace mu::ui;
using MoveDirection = KeyNavigationController::MoveDirection;
// algorithms
template<class T>
static IKeyNavigation::Index determinateExtremeIndex(const QSet<T*>& set, MoveDirection direction)
{
IKeyNavigation::Index index;
switch (direction) {
case MoveDirection::Right: {
index.column = -1;
// find min row
index.row = std::numeric_limits<int>::max();
for (T* v : set) {
if (v->index().row < index.row) {
index.row = v->index().row;
}
}
} break;
case MoveDirection::Left: {
index.column = std::numeric_limits<int>::max();
// find max row
index.row = -1;
for (T* v : set) {
if (v->index().row > index.row) {
index.row = v->index().row;
}
}
} break;
case MoveDirection::Down: {
index.row = -1;
// find min column
index.column = std::numeric_limits<int>::max();
for (T* v : set) {
if (v->index().column < index.column) {
index.column = v->index().column;
}
}
} break;
case MoveDirection::Up: {
index.row = std::numeric_limits<int>::max();
// find max row
index.column = -1;
for (T* v : set) {
if (v->index().column > index.column) {
index.column = v->index().row;
}
}
} break;
}
return index;
}
template<class T>
static T* findNearestEnabled(const QSet<T*>& set, const IKeyNavigation::Index& currentIndex, MoveDirection direction)
{
@ -92,6 +38,32 @@ static T* findNearestEnabled(const QSet<T*>& set, const IKeyNavigation::Index& c
}
switch (direction) {
case MoveDirection::First: {
if (!ret) {
ret = v;
continue;
}
if (v->index().row <= ret->index().row) {
if (v->index().column <= ret->index().column) {
ret = v;
continue;
}
}
} break;
case MoveDirection::Last: {
if (!ret) {
ret = v;
continue;
}
if (v->index().row >= ret->index().row) {
if (v->index().column >= ret->index().column) {
ret = v;
continue;
}
}
} break;
case MoveDirection::Right: {
if (v->index().row != currentIndex.row) {
continue;
@ -163,9 +135,7 @@ static T* findNearestEnabled(const QSet<T*>& set, const IKeyNavigation::Index& c
}
template<class T>
static T* firstEnabled(const QSet<T*>& set,
const IKeyNavigation::Index& currentIndex = IKeyNavigation::Index(),
MoveDirection direction = MoveDirection::Right)
static T* firstEnabled(const QSet<T*>& set, const IKeyNavigation::Index& currentIndex, MoveDirection direction)
{
if (set.empty()) {
return nullptr;
@ -175,31 +145,41 @@ static T* firstEnabled(const QSet<T*>& set,
return nullptr;
}
if (currentIndex.column < 0 && currentIndex.row < 0) {
return findNearestEnabled<T>(set, determinateExtremeIndex(set, direction), direction);
return findNearestEnabled<T>(set, currentIndex, direction);
}
template<class T>
static T* firstEnabled(const QSet<T*>& set)
{
if (set.empty()) {
return nullptr;
}
return findNearestEnabled<T>(set, IKeyNavigation::Index(), MoveDirection::First);
}
template<class T>
static T* lastEnabled(const QSet<T*>& set, const IKeyNavigation::Index& currentIndex, MoveDirection direction)
{
if (set.empty()) {
return nullptr;
}
IF_ASSERT_FAILED(direction == MoveDirection::Left || (direction == MoveDirection::Up)) {
return nullptr;
}
return findNearestEnabled<T>(set, currentIndex, direction);
}
template<class T>
static T* lastEnabled(const QSet<T*>& set,
const IKeyNavigation::Index& currentIndex = IKeyNavigation::Index(),
MoveDirection direction = MoveDirection::Left)
static T* lastEnabled(const QSet<T*>& set)
{
if (set.empty()) {
return nullptr;
}
IF_ASSERT_FAILED(direction == MoveDirection::Left || direction == MoveDirection::Up) {
return nullptr;
}
if (currentIndex.column < 0 && currentIndex.row < 0) {
return findNearestEnabled<T>(set, determinateExtremeIndex(set, direction), direction);
}
return findNearestEnabled<T>(set, currentIndex, direction);
return findNearestEnabled<T>(set, IKeyNavigation::Index(), MoveDirection::Last);
}
template<class T>
@ -250,11 +230,18 @@ void KeyNavigationController::init()
dispatcher()->reg(this, "nav-prev-section", this, &KeyNavigationController::goToPrevSection);
dispatcher()->reg(this, "nav-next-subsection", this, &KeyNavigationController::goToNextSubSection);
dispatcher()->reg(this, "nav-prev-subsection", this, &KeyNavigationController::goToPrevSubSection);
dispatcher()->reg(this, "nav-trigger-control", this, &KeyNavigationController::doTriggerControl);
dispatcher()->reg(this, "nav-right", this, &KeyNavigationController::onRight);
dispatcher()->reg(this, "nav-left", this, &KeyNavigationController::onLeft);
dispatcher()->reg(this, "nav-up", this, &KeyNavigationController::onUp);
dispatcher()->reg(this, "nav-down", this, &KeyNavigationController::onDown);
dispatcher()->reg(this, "nav-trigger", this, &KeyNavigationController::doTriggerControl);
dispatcher()->reg(this, "nav-first-control", this, &KeyNavigationController::goToFirstControl); // typically Home key
dispatcher()->reg(this, "nav-last-control", this, &KeyNavigationController::goToLastControl); // typically End key
dispatcher()->reg(this, "nav-nextrow-control", this, &KeyNavigationController::goToNextRowControl); // typically PageDown key
dispatcher()->reg(this, "nav-prevrow-control", this, &KeyNavigationController::goToPrevRowControl); // typically PageUp key
}
void KeyNavigationController::reg(IKeyNavigationSection* s)
@ -594,6 +581,80 @@ void KeyNavigationController::onUp()
}
}
void KeyNavigationController::goToFirstControl()
{
LOGI() << "====";
goToControl(MoveDirection::First);
}
void KeyNavigationController::goToLastControl()
{
LOGI() << "====";
goToControl(MoveDirection::Last);
}
void KeyNavigationController::goToNextRowControl()
{
LOGI() << "====";
IKeyNavigationSubSection* activeSubSec = activeSubSection();
if (!activeSubSec) {
return;
}
IKeyNavigationControl* activeControl = findActive(activeSubSec->controls());
if (activeControl) {
doDeactivateControl(activeControl);
}
IKeyNavigationControl* toControl = nullptr;
if (activeControl) {
IKeyNavigation::Index index = activeControl->index();
index.column = 0;
toControl = nextEnabled(activeSubSec->controls(), index, MoveDirection::Down);
if (!toControl) { // last row
toControl = firstEnabled(activeSubSec->controls());
}
} else {
toControl = firstEnabled(activeSubSec->controls());
}
if (toControl) {
doActivateControl(toControl);
}
}
void KeyNavigationController::goToPrevRowControl()
{
LOGI() << "====";
IKeyNavigationSubSection* activeSubSec = activeSubSection();
if (!activeSubSec) {
return;
}
IKeyNavigationControl* activeControl = findActive(activeSubSec->controls());
if (activeControl) {
doDeactivateControl(activeControl);
}
IKeyNavigationControl* toControl = nullptr;
if (activeControl) {
IKeyNavigation::Index index = activeControl->index();
index.column = 0;
toControl = prevEnabled(activeSubSec->controls(), index, MoveDirection::Up);
if (!toControl) { // first row
toControl = lastEnabled(activeSubSec->controls());
}
} else {
toControl = lastEnabled(activeSubSec->controls());
}
if (toControl) {
doActivateControl(toControl);
}
}
void KeyNavigationController::goToControl(MoveDirection direction, IKeyNavigationSubSection* activeSubSec)
{
LOGI() << "direction: " << direction;
@ -614,6 +675,12 @@ void KeyNavigationController::goToControl(MoveDirection direction, IKeyNavigatio
IKeyNavigationControl* toControl = nullptr;
switch (direction) {
case MoveDirection::First: {
toControl = firstEnabled(activeSubSec->controls());
} break;
case MoveDirection::Last: {
toControl = lastEnabled(activeSubSec->controls());
} break;
case MoveDirection::Right: {
if (!activeControl) { // no any active
toControl = firstEnabled(activeSubSec->controls(), IKeyNavigation::Index(), direction);

View file

@ -35,7 +35,9 @@ public:
KeyNavigationController() = default;
enum MoveDirection {
Right = 0,
First = 0,
Last,
Right,
Left,
Up,
Down
@ -52,7 +54,12 @@ private:
void goToNextSubSection();
void goToPrevSubSection();
void goToControl(MoveDirection direction, IKeyNavigationSubSection* activeSubSec);
void goToFirstControl();
void goToLastControl();
void goToNextRowControl();
void goToPrevRowControl();
void goToControl(MoveDirection direction, IKeyNavigationSubSection* activeSubSec = nullptr);
void onLeft();
void onRight();

View file

@ -48,7 +48,19 @@ const UiActionList KeyNavigationUiActions::m_actions = {
UiAction("nav-down",
mu::context::UiCtxAny
),
UiAction("nav-trigger",
UiAction("nav-trigger-control",
mu::context::UiCtxAny
),
UiAction("nav-first-control",
mu::context::UiCtxAny
),
UiAction("nav-last-control",
mu::context::UiCtxAny
),
UiAction("nav-nextrow-control",
mu::context::UiCtxAny
),
UiAction("nav-prevrow-control",
mu::context::UiCtxAny
)
};

View file

@ -33,17 +33,8 @@ FocusableControl {
opacity: root.enabled ? 1.0 : ui.theme.itemOpacityDisabled
onInternalClicked: {
root.clicked()
}
onInternalPressAndHold: {
root.pressAndHold()
}
onInternalTriggered: {
root.clicked()
}
mouseArea.onClicked: root.clicked()
mouseArea.onPressAndHold: root.pressAndHold()
mouseArea.hoverEnabled: true
mouseArea.onContainsMouseChanged: {
@ -58,6 +49,8 @@ FocusableControl {
}
}
keynav.onTriggered: root.clicked()
background.color: normalStateColor
background.opacity: ui.theme.buttonOpacityNormal
background.radius: 3

View file

@ -12,13 +12,6 @@ FocusScope {
property alias keynav: keynavItem
signal internalPressed()
signal internalReleased()
signal internalClicked()
signal internalPressAndHold()
signal internalTriggered()
function insureActiveFocus() {
if (!root.activeFocus) {
root.forceActiveFocus()
@ -39,10 +32,6 @@ FocusScope {
root.insureActiveFocus()
}
}
onTriggered: {
root.internalTriggered()
}
}
Rectangle {
@ -64,19 +53,6 @@ FocusScope {
onClicked: {
root.insureActiveFocus()
root.internalClicked()
}
onPressAndHold: {
root.internalPressAndHold()
}
onPressed: {
root.internalPressed()
}
onReleased: {
root.internalReleased()
}
}
}

View file

@ -2,13 +2,13 @@ import QtQuick 2.15
import MuseScore.Ui 1.0
Item {
FocusableControl {
id: root
property string hint
property bool isSelected: false
property alias radius: background.radius
property alias radius: root.background.radius
property color normalStateColor: "transparent"
property color hoveredStateColor: privateProperties.defaultColor
@ -24,20 +24,31 @@ Item {
Accessible.selectable: true
Accessible.selected: isSelected
mouseArea.hoverEnabled: root.visible
mouseArea.onHoveredChanged: root.hovered(mouseArea.containsMouse, mouseArea.mouseX, mouseArea.mouseY)
mouseArea.onClicked: root.clicked()
mouseArea.onDoubleClicked: root.doubleClicked()
mouseArea.onContainsMouseChanged: {
if (!Boolean(root.hint)) {
return
}
if (mouseArea.containsMouse) {
ui.tooltip.show(this, root.hint)
} else {
ui.tooltip.hide(this)
}
}
QtObject {
id: privateProperties
property color defaultColor: ui.theme.buttonColor
}
Rectangle {
id: background
anchors.fill: parent
color: normalStateColor
opacity: root.enabled ? 1 : ui.theme.itemOpacityDisabled
}
background.opacity: root.enabled ? 1 : ui.theme.itemOpacityDisabled
states: [
State {
@ -45,7 +56,7 @@ Item {
when: mouseArea.containsMouse && !mouseArea.pressed && !root.isSelected
PropertyChanges {
target: background
target: root.background
opacity: ui.theme.buttonOpacityHover
color: hoveredStateColor
}
@ -56,7 +67,7 @@ Item {
when: mouseArea.pressed && !root.isSelected
PropertyChanges {
target: background
target: root.background
opacity: ui.theme.buttonOpacityHit
color: pressedStateColor
}
@ -67,42 +78,10 @@ Item {
when: root.isSelected
PropertyChanges {
target: background
target: root.background
opacity: ui.theme.accentOpacityHit
color: ui.theme.accentColor
}
}
]
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: root.visible
onHoveredChanged: {
root.hovered(mouseArea.containsMouse, mouseX, mouseY)
}
onClicked: {
root.clicked()
}
onDoubleClicked: {
root.doubleClicked()
}
onContainsMouseChanged: {
if (!Boolean(root.hint)) {
return
}
if (containsMouse) {
ui.tooltip.show(this, root.hint)
} else {
ui.tooltip.hide(this)
}
}
}
}

View file

@ -12,6 +12,7 @@ import MuseScore.Instruments 1.0
import "internal"
Item {
id: root
property KeyNavigationSection keynavSection: null
@ -37,6 +38,7 @@ Item {
name: "InstrumentsTree"
section: root.keynavSection
direction: KeyNavigationSubSection.Both
enabled: root.visible
order: 3
}
@ -57,6 +59,7 @@ Item {
Layout.rightMargin: contentColumn.sideMargin
keynav.section: root.keynavSection
keynav.enabled: root.visible
keynav.order: 2
isMovingUpAvailable: instrumentTreeModel.isMovingUpAvailable

View file

@ -31,7 +31,7 @@ RowLayout {
KeyNavigationSubSection {
id: keynavSub
name: "InstrumentsControlPanel"
name: "InstrumentsHeader"
}
FlatButton {

View file

@ -262,7 +262,6 @@ bool InstrumentPanelTreeModel::moveRows(const QModelIndex& sourceParent, int sou
bool InstrumentPanelTreeModel::isSelected(const QModelIndex& rowIndex) const
{
TRACEFUNC;
if (m_selectionModel->selectedIndexes().isEmpty()) {
return false;
}
@ -346,7 +345,6 @@ int InstrumentPanelTreeModel::columnCount(const QModelIndex&) const
QVariant InstrumentPanelTreeModel::data(const QModelIndex& index, int role) const
{
TRACEFUNC;
if (!index.isValid() && role != ItemRole) {
return QVariant();
}

View file

@ -8,6 +8,8 @@ Rectangle {
property alias keynav: keynavSub
signal activeFocusRequested()
Component.onCompleted: {
toolbarModel.load()
}
@ -15,6 +17,12 @@ Rectangle {
KeyNavigationSubSection {
id: keynavSub
name: "NotationToolBar"
onActiveChanged: {
if (active) {
root.activeFocusRequested()
root.forceActiveFocus()
}
}
}
NotationToolBarModel {

View file

@ -17,23 +17,22 @@
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
import QtQuick 2.8
import QtQuick 2.15
import QtQuick.Controls 2.1
import QtQuick.Window 2.2
import MuseScore.Ui 1.0
import MuseScore.UiComponents 1.0
import MuseScore.Palette 1.0
// TODO: make some properties 'property alias`?
// and `readonly property`?
import "internal"
Rectangle {
id: palettesWidget
readonly property PaletteWorkspace paletteWorkspace: paletteRootModel.paletteWorkspace
property KeyNavigationSection keynavSection: null
readonly property bool hasFocus: Window.activeFocusItem
readonly property PaletteWorkspace paletteWorkspace: paletteRootModel.paletteWorkspace
implicitHeight: 4 * palettesWidgetHeader.implicitHeight
implicitWidth: paletteTree.implicitWidth
@ -46,14 +45,6 @@ Rectangle {
color: ui.theme.backgroundPrimaryColor
FocusableItem {
id: focusBreaker
onActiveFocusChanged: {
parent.focus = false
}
}
PaletteRootModel {
id: paletteRootModel
@ -77,6 +68,9 @@ Rectangle {
rightMargin: 12
}
keynav.section: palettesWidget.keynavSection
keynav.order: 2
onAddCustomPaletteRequested: paletteTree.insertCustomPalette(0, paletteName);
}
@ -96,6 +90,11 @@ Rectangle {
id: paletteTree
clip: true
paletteWorkspace: palettesWidget.paletteWorkspace
backgroundColor: palettesWidget.color
keynav.section: palettesWidget.keynavSection
keynav.order: 3
keynav.enabled: paletteTree.visible
filter: palettesWidgetHeader.searchText
enableAnimations: !palettesWidgetHeader.searching

View file

@ -50,6 +50,10 @@ GridView {
property bool enableAnimations: true
property KeyNavigationSubSection keynavSubSection: null
property int keynavRow: 0
property int keynavCol: 1
states: [
State {
name: "default"
@ -97,7 +101,8 @@ GridView {
cellWidth: stretchWidth ? Math.floor(Utils.stretched(cellDefaultWidth, width)) : cellDefaultWidth
cellHeight: cellSize.height
readonly property real ncolumns: Math.floor(width / cellWidth);
readonly property int nrows: Math.max(0, Math.floor(height / cellHeight))
readonly property int ncolumns: Math.max(0, Math.floor(width / cellWidth))
readonly property real lastColumnCellWidth : cellWidth + (width % cellWidth) // width of last cell in a row: might be stretched to avoid a gap at row end
signal moreButtonClicked()
@ -164,7 +169,12 @@ GridView {
id: moreButton
anchors.fill: parent
activeFocusOnTab: this === paletteTree.currentTreeItem
keynav.subsection: paletteView.keynavSubSection
//! NOTE Just Up/Down navigation now
keynav.row: paletteView.ncells + paletteView.keynavRow
keynav.column: 1
keynav.enabled: paletteView.visible
onActiveFocusChanged: {
if (activeFocus) {
@ -183,42 +193,6 @@ GridView {
pressedStateColor: ui.theme.accentColor
onClicked: paletteView.moreButtonClicked()
Keys.onShortcutOverride: {
// Intercept all keys that we want to use with Keys.onPressed
// in case they are assigned as shortcuts in Preferences.
event.accepted = true; // intercept everything
switch (event.key) {
case Qt.Key_Up:
case Qt.Key_Down:
return;
}
event.accepted = false; // allow key to function as shortcut (don't intercept)
}
Keys.onPressed: {
// NOTE: All keys must be intercepted with Keys.onShortcutOverride.
switch (event.key) {
case Qt.Key_Up:
focusPreviousItem();
break;
case Qt.Key_Down:
paletteTree.focusNextItem(false);
break;
default:
return; // don't accept event
}
event.accepted = true;
}
function focusPreviousItem() {
if (paletteView.count == 0) {
paletteTree.currentItem.forceActiveFocus();
} else {
paletteView.currentIndex = paletteView.count - 1
paletteView.currentItem.forceActiveFocus();
}
}
}
}
@ -408,34 +382,6 @@ GridView {
Utils.removeSelectedItems(paletteController, selectionModel, paletteRootIndex);
}
function focusNextItem(flags) {
if (flags === undefined) {
flags = ItemSelectionModel.ClearAndSelect;
}
if (currentIndex == count - 1) {
if (moreButton.visible) {
moreButton.forceActiveFocus();
} else {
paletteTree.focusNextItem(false);
}
} else {
currentIndex++; // next grid item
}
}
function focusPreviousItem(flags) {
if (flags === undefined) {
flags = ItemSelectionModel.ClearAndSelect;
}
if (currentIndex == 0) {
paletteTree.currentItem.forceActiveFocus();
} else {
currentIndex--; // previous grid item
}
}
function focusFirstItem() {
if (count == 0 && moreButton.visible) {
moreButton.forceActiveFocus();
@ -504,48 +450,6 @@ GridView {
}
}
Keys.onShortcutOverride: {
// Intercept all keys that we want to use with Keys.onPressed
// in case they are assigned as shortcuts in Preferences.
event.accepted = true; // intercept everything
switch (event.key) {
case Qt.Key_Up:
case Qt.Key_Down:
case Qt.Key_Left:
case Qt.Key_Right:
case Qt.Key_Backspace:
case Qt.Key_Delete:
return;
}
event.accepted = false; // allow key to function as shortcut (don't intercept)
}
Keys.onPressed: {
// NOTE: All keys must be intercepted with Keys.onShortcutOverride.
switch (event.key) {
case Qt.Key_Up:
focusPreviousItem();
break;
case Qt.Key_Down:
focusNextItem();
break;
case Qt.Key_Left:
paletteTree.currentItem.forceActiveFocus();
break;
case Qt.Key_Right:
if (moreButton.visible)
moreButton.forceActiveFocus();
break;
case Qt.Key_Backspace:
case Qt.Key_Delete:
removeSelectedCells();
break;
default:
return; // don't accept event
}
event.accepted = true;
}
Rectangle {
id: draggedIcon
@ -576,6 +480,10 @@ GridView {
property var modelIndex: paletteView.model.modelIndex(index)
property var parentModelIndex: paletteView.paletteRootIndex
//! NOTE Please, don't remove (igor.korsukov@gmail.com)
//property int cellRow: paletteView.ncolumns == 0 ? 0 : Math.floor(model.index / paletteView.ncolumns)
//property int cellCol: model.index - (cellRow * paletteView.ncolumns)
onActiveFocusChanged: {
if (activeFocus) {
paletteTree.currentTreeItem = this;
@ -593,7 +501,17 @@ GridView {
width: paletteView.cellWidth
height: paletteView.cellHeight
activeFocusOnTab: this === paletteTree.currentTreeItem
keynav.subsection: paletteView.keynavSubSection
//! NOTE Please, don't remove (igor.korsukov@gmail.com)
//keynav.row: paletteCell.cellRow + paletteView.keynavRow
//keynav.column: paletteCell.cellCol + paletteView.keynavCol
//! NOTE Just Up/Down navigation now
keynav.row: model.index + paletteView.keynavRow
keynav.column: 1
keynav.enabled: paletteView.visible
keynav.onTriggered: paletteCell.doClicked()
IconView {
anchors.fill: parent
@ -605,108 +523,37 @@ GridView {
Accessible.name: model.accessibleText;
Keys.onShortcutOverride: {
// Intercept all keys that we want to use with Keys.onPressed
// in case they are assigned as shortcuts in Preferences.
event.accepted = true; // intercept everything
switch (event.key) {
case Qt.Key_Space:
case Qt.Key_Enter:
case Qt.Key_Return:
case Qt.Key_Menu:
case Qt.Key_Asterisk:
return;
}
if (event.key === Qt.Key_F10 && event.modifiers & Qt.ShiftModifier) {
return;
}
if (event.text.match(/[^\x00-\x20\x7F]+$/) !== null) {
return;
}
event.accepted = false; // allow key to function as shortcut (don't intercept)
// leftClickArea
mouseArea.drag.target: this
mouseArea.onPressed: {
paletteView.currentIndex = paletteCell.rowIndex;
paletteCell.forceActiveFocus();
paletteView.updateSelection(true);
paletteCell.beginDrag();
}
Keys.onPressed: {
// NOTE: All keys must be intercepted with Keys.onShortcutOverride.
const shiftHeld = event.modifiers & Qt.ShiftModifier;
const ctrlHeld = event.modifiers & Qt.ControlModifier;
switch (event.key) {
case Qt.Key_Space:
if (paletteTree.typeAheadStr.length) {
paletteView.typeAheadFind(' ');
} else {
paletteView.updateSelection(true);
}
break;
case Qt.Key_Enter:
case Qt.Key_Return:
paletteView.selectionModel.setCurrentIndex(modelIndex, ItemSelectionModel.ClearAndSelect);
paletteView.paletteController.applyPaletteElement(modelIndex, ui.keyboardModifiers());
break;
case Qt.Key_F10:
if (!shiftHeld) {
return;
}
// fallthrough
case Qt.Key_Menu:
showCellMenu();
break;
case Qt.Key_Asterisk:
if (paletteTree.typeAheadStr.length) {
paletteView.typeAheadFind('*');
} else if (!paletteTree.expandCollapseAll(null)) {
paletteTree.currentItem.forceActiveFocus();
}
break;
default:
if (event.text.match(/[^\x00-\x20\x7F]+$/) !== null) {
// Pressed non-control character(s) (e.g. "D") so go
// to matching item (e.g. "D Major" in keysig palette)
paletteView.typeAheadFind(event.text);
} else {
return; // don't accept event
}
function doClicked() {
if (paletteView.paletteController.applyPaletteElement(paletteCell.modelIndex, ui.keyboardModifiers())) {
paletteView.selectionModel.setCurrentIndex(paletteCell.modelIndex, ItemSelectionModel.Current);
}
event.accepted = true;
}
MouseArea {
id: leftClickArea
anchors.fill: parent
drag.target: this
onClicked: paletteCell.doClicked()
onPressed: {
paletteView.currentIndex = paletteCell.rowIndex;
paletteCell.forceActiveFocus();
paletteView.updateSelection(true);
paletteCell.beginDrag();
}
onClicked: {
if (paletteView.paletteController.applyPaletteElement(paletteCell.modelIndex, ui.keyboardModifiers())) {
paletteView.selectionModel.setCurrentIndex(paletteCell.modelIndex, ItemSelectionModel.Current);
}
}
onDoubleClicked: {
const index = paletteCell.modelIndex;
paletteView.selectionModel.setCurrentIndex(index, ItemSelectionModel.Current);
paletteView.paletteController.applyPaletteElement(index, mouse.modifiers);
}
onDoubleClicked: {
const index = paletteCell.modelIndex;
paletteView.selectionModel.setCurrentIndex(index, ItemSelectionModel.Current);
paletteView.paletteController.applyPaletteElement(index, mouseArea.mouse.modifiers);
}
MouseArea {
id: rightClickArea
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: showCellMenu(true)
}
Drag.active: leftClickArea.drag.active
Drag.active: mouseArea.drag.active
Drag.dragType: Drag.Automatic
Drag.supportedActions: Qt.CopyAction | (model.editable ? Qt.MoveAction : 0)
Drag.mimeData: Drag.active ? mimeData : {}

View file

@ -29,25 +29,44 @@ import "utils.js" as Utils
ListView {
id: paletteTree
Accessible.name: qsTrc("palette", "Palettes Tree, contains %n palette(s)", "", count)
activeFocusOnTab: true // allow focus even when empty
property PaletteWorkspace paletteWorkspace
property var paletteModel: Boolean(paletteWorkspace) ? paletteWorkspace.mainPaletteModel : null
property PaletteController paletteController: paletteWorkspace ? paletteWorkspace.mainPaletteController : null
property alias keynav: keynavTree
// Scroll palettes list when dragging a palette close to the list's border
property bool itemDragged: false
preferredHighlightBegin: Math.min(48, Math.floor(0.1 * height))
preferredHighlightEnd: Math.ceil(height - preferredHighlightBegin)
highlightRangeMode: itemDragged ? ListView.ApplyRange : ListView.NoHighlightRange
property Item currentTreeItem: currentItem // most recently focused item at any level of the tree
property string filter: ""
property bool searchOpened: false
property bool enableAnimations: true
property int expandDuration: enableAnimations ? 150 : 0 // duration of expand / collapse animations
property string backgroundColor: "#ffffff"
preferredHighlightBegin: Math.min(48, Math.floor(0.1 * height))
preferredHighlightEnd: Math.ceil(height - preferredHighlightBegin)
highlightRangeMode: itemDragged ? ListView.ApplyRange : ListView.NoHighlightRange
Accessible.name: qsTrc("palette", "Palettes Tree, contains %n palette(s)", "", count)
KeyNavigationSubSection {
id: keynavTree
name: "PalettesTree"
direction: KeyNavigationSubSection.Both
onActiveChanged: {
if (active) {
paletteTree.forceActiveFocus()
}
}
}
onSearchOpenedChanged: {
if (paletteWorkspace) {
paletteWorkspace.setSearching(searchOpened)
@ -65,9 +84,6 @@ ListView {
}
}
property bool enableAnimations: true
property int expandDuration: enableAnimations ? 150 : 0 // duration of expand / collapse animations
function insertCustomPalette(idx, paletteName) {
if (paletteTree.paletteController.insertNewItem(paletteTreeDelegateModel.rootIndex, idx, paletteName)) {
positionViewAtIndex(idx, ListView.Contain)
@ -132,56 +148,6 @@ ListView {
Utils.removeSelectedItems(paletteController, paletteSelectionModel, parentIndex);
}
Keys.onShortcutOverride: {
// Intercept all keys that we want to use with Keys.onPressed
// in case they are assigned as shortcuts in Preferences.
event.accepted = true; // intercept everything
switch (event.key) {
case Qt.Key_Down:
case Qt.Key_Up:
case Qt.Key_Home:
case Qt.Key_End:
case Qt.Key_PageUp:
case Qt.Key_PageDown:
case Qt.Key_Backspace:
case Qt.Key_Delete:
return;
}
event.accepted = false; // allow key to function as shortcut (don't intercept)
}
Keys.onPressed: {
// NOTE: All keys must be intercepted with Keys.onShortcutOverride.
switch (event.key) {
case Qt.Key_Down:
focusNextItem();
break;
case Qt.Key_Up:
focusPreviousItem();
break;
case Qt.Key_Home:
focusFirstItem();
break;
case Qt.Key_End:
focusLastItem();
break;
case Qt.Key_PageUp:
focusPreviousPageItem();
break;
case Qt.Key_PageDown:
focusNextPageItem();
break;
case Qt.Key_Backspace:
case Qt.Key_Delete:
expandedPopupIndex = null;
removeSelectedItems();
break;
default:
return; // don't accept event
}
event.accepted = true;
}
displaced: Transition {
enabled: paletteTree.enableAnimations
NumberAnimation { property: "y"; duration: 150 }
@ -200,103 +166,6 @@ ListView {
return { display: "", gridSize: Qt.size(1, 1), drawGrid: false, custom: false, editable: false, expanded: false };
}
function focusNextItem(includeChildren) {
if (includeChildren === undefined) { // https://stackoverflow.com/a/44128406
includeChildren = true;
}
if (includeChildren && currentItem.expanded) {
currentItem.focusFirstItem();
return;
}
if (currentIndex == count - 1) {
return; // no next item
}
incrementCurrentIndex();
currentItem.forceActiveFocus();
positionViewAtIndex(currentIndex, ListView.Contain);
}
function focusPreviousItem(includeChildren) {
if (includeChildren === undefined) { // https://stackoverflow.com/a/44128406
includeChildren = true;
}
if (currentIndex == 0) {
return; // no previous item
}
decrementCurrentIndex();
if (includeChildren && currentItem.expanded) {
currentItem.focusLastItem();
} else {
currentItem.forceActiveFocus();
}
positionViewAtIndex(currentIndex, ListView.Contain);
}
function focusNextPageItem() {
if (currentIndex < count - 1) {
currentIndex++; // move by at least one item
// try to keep going, but new item must stay entirely in view
var distance = currentItem.height;
while (currentIndex < count - 1) {
currentIndex++; // try another
distance += currentItem.height;
if (distance > height) {
currentIndex--; // too far, go back one
break;
}
}
}
currentItem.forceActiveFocus();
positionViewAtIndex(currentIndex, ListView.Contain);
}
function focusPreviousPageItem() {
if (currentIndex > 0) {
currentIndex--; // move by at least one item
// try to keep going, but new item must stay entirely in view
var distance = currentItem.height;
while (currentIndex > 0) {
currentIndex--; // try another
distance += currentItem.height;
if (distance > height) {
currentIndex++; // too far, go back one
break;
}
}
}
currentItem.forceActiveFocus();
positionViewAtIndex(currentIndex, ListView.Contain);
}
function focusFirstItem() {
currentIndex = 0;
currentItem.forceActiveFocus();
positionViewAtIndex(currentIndex, ListView.Contain);
}
function focusLastItem() {
currentIndex = count - 1;
if (currentItem.expanded) {
currentItem.focusLastItem();
} else {
currentItem.forceActiveFocus();
}
positionViewAtIndex(currentIndex, ListView.Contain);
}
function focusNextMatchingItem(str, startIndex) {
const modelIndex = paletteModel.index(startIndex, 0);
const matchedIndexList = paletteModel.match(modelIndex, Qt.ToolTipRole, str);
@ -373,6 +242,7 @@ ListView {
topPadding: 0
bottomPadding: expanded ? 4 : 0
property int rowIndex: index
property int keynavRow: (index + 1) * 10000 // to make unique
property var modelIndex: paletteTree.model.modelIndex(index, 0)
onActiveFocusChanged: {
@ -386,14 +256,6 @@ ListView {
paletteTree.implicitWidth = Math.max(paletteTree.implicitWidth, w);
}
function focusFirstItem() {
mainPalette.focusFirstItem();
}
function focusLastItem() {
mainPalette.focusLastItem();
}
property bool expanded: filter.length || model.expanded
function toggleExpand() {
@ -418,13 +280,17 @@ ListView {
property bool selected: paletteSelectionModel.hasSelection ? paletteSelectionModel.isSelected(modelIndex) : false
onClicked: {
function doItemClicked() {
forceActiveFocus();
const cmd = selected ? ItemSelectionModel.Toggle : ItemSelectionModel.ClearAndSelect;
paletteSelectionModel.setCurrentIndex(modelIndex, cmd);
paletteTree.currentIndex = index;
}
onClicked: {
control.doItemClicked()
}
onDoubleClicked: {
forceActiveFocus();
paletteSelectionModel.setCurrentIndex(modelIndex, ItemSelectionModel.Deselect);
@ -432,9 +298,21 @@ ListView {
}
background: ListItemBlank {
background.color: paletteTree.backgroundColor
visible: !control.Drag.active
isSelected: control.selected
keynav.name: "PaletteTreeItemDelegate"
keynav.subsection: keynavTree
keynav.row: control.keynavRow
keynav.column: 0
enabled: control.visible
keynav.onActiveChanged: {
if (keynav.active && !control.selected) {
control.doItemClicked()
}
paletteTree.positionViewAtIndex(control.rowIndex, ListView.Contain);
}
}
highlighted: (activeFocus && !selected) || DelegateModel.isUnresolved
@ -449,94 +327,11 @@ ListView {
property size cellSize: model.gridSize
property bool drawGrid: model.drawGrid
activeFocusOnTab: this === paletteTree.currentTreeItem
function hidePalette() {
paletteTree.expandedPopupIndex = null;
paletteTree.paletteController.remove(modelIndex);
}
Keys.onShortcutOverride: {
// Intercept all keys that we want to use with Keys.onPressed
// in case they are assigned as shortcuts in Preferences.
event.accepted = true; // intercept everything
switch (event.key) {
case Qt.Key_Right:
case Qt.Key_Plus:
case Qt.Key_Left:
case Qt.Key_Minus:
case Qt.Key_Space:
case Qt.Key_Enter:
case Qt.Key_Return:
case Qt.Key_Menu:
case Qt.Key_Asterisk:
return;
}
if (event.key === Qt.Key_F10 && event.modifiers & Qt.ShiftModifier) {
return;
}
if (event.text.match(/[^\x00-\x20\x7F]+$/) !== null) {
return;
}
event.accepted = false; // allow key to function as shortcut (don't intercept)
}
Keys.onPressed: {
// NOTE: All keys must be intercepted with Keys.onShortcutOverride.
switch (event.key) {
case Qt.Key_Right:
case Qt.Key_Plus:
if (!expanded) {
toggleExpand();
} else if (event.key === Qt.Key_Right) {
focusFirstItem();
}
break;
case Qt.Key_Left:
case Qt.Key_Minus:
if (expanded)
toggleExpand();
break;
case Qt.Key_Space:
if (paletteTree.typeAheadStr.length) {
paletteTree.typeAheadFind(' ');
break;
}
// fallthrough
case Qt.Key_Enter:
case Qt.Key_Return:
toggleExpand();
break;
case Qt.Key_F10:
if (!(event.modifiers & Qt.ShiftModifier)) {
return;
}
// fallthrough
case Qt.Key_Menu:
paletteHeader.showPaletteMenu();
break;
case Qt.Key_Asterisk:
if (paletteTree.typeAheadStr.length) {
paletteTree.typeAheadFind('*');
} else {
paletteTree.expandCollapseAll(null);
}
break;
default:
if (event.text.match(/[^\x00-\x20\x7F]+$/) !== null) {
// Pressed non-control character(s) (e.g. "L")
// so go to matching palette (e.g. "Lines")
paletteTree.typeAheadFind(event.text);
} else {
return; // don't accept event
}
}
event.accepted = true;
}
text: filter.length ? qsTrc("palette", "%1, contains %n matching element(s)", "palette", mainPalette.count).arg(model.accessibleText)
: model.expanded ? qsTrc("palette", "%1 expanded", "tree item not collapsed").arg(model.accessibleText)
: model.accessibleText
@ -577,8 +372,8 @@ ListView {
if (dropAction == Qt.MoveAction) {
controller.move(
root, rowIndex,
root, destIndex);
root, rowIndex,
root, destIndex);
}
}
@ -647,10 +442,13 @@ ListView {
hovered: control.hovered
text: model.display
keynavSubsection: keynavTree
keynavRow: control.keynavRow
hidePaletteElementVisible: {
return !control.selected && control.expanded
&& paletteSelectionModel.hasSelection && paletteSelectionModel.columnIntersectsSelection(0, control.modelIndex)
&& paletteTree.paletteModel.parent(paletteSelectionModel.currentIndex) === control.modelIndex; // HACK to work around a (possible?) bug in columnIntersectsSelection
&& paletteSelectionModel.hasSelection && paletteSelectionModel.columnIntersectsSelection(0, control.modelIndex)
&& paletteTree.paletteModel.parent(paletteSelectionModel.currentIndex) === control.modelIndex; // HACK to work around a (possible?) bug in columnIntersectsSelection
}
custom: model.custom
@ -706,6 +504,9 @@ ListView {
id: mainPalette
anchors { fill: parent; margins: parent.padding }
keynavSubSection: keynavTree
keynavRow: control.keynavRow + 1
cellSize: control.cellSize
drawGrid: control.drawGrid
@ -811,14 +612,4 @@ ListView {
// placeholder footer item to reserve a space for "More" popup to expand
footer: Item { height: 0 }
Connections {
target: palettesWidget
function onHasFocusChanged() {
if (!palettesWidget.hasFocus) {
paletteSelectionModel.clearSelection();
expandedPopupIndex = null;
}
}
}
}

View file

@ -17,12 +17,12 @@
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
import QtQuick 2.8
import QtQuick 2.15
import QtQuick.Controls 2.1
import MuseScore.Palette 1.0
import MuseScore.UiComponents 1.0
import MuseScore.Ui 1.0
import MuseScore.UiComponents 1.0
import MuseScore.Palette 1.0
import "utils.js" as Utils
@ -36,6 +36,8 @@ Item {
property alias popupMaxHeight: palettePopup.maxHeight
property alias keynav: keynavSub
signal addCustomPaletteRequested(var paletteName)
implicitHeight: childrenRect.height
@ -55,20 +57,39 @@ Item {
}
}
KeyNavigationSubSection {
id: keynavSub
name: "PalettesHeader"
onActiveChanged: {
if (active) {
header.forceActiveFocus()
}
}
}
FlatButton {
id: morePalettesButton
anchors.left: parent.left
anchors.right: searchTextButton.left
anchors.rightMargin: 8
objectName: "AddPalettesBtn"
keynav.subsection: keynavSub
keynav.order: 1
enabled: !searchTextInput.visible
text: qsTrc("palette", "Add Palettes")
onClicked: palettePopup.visible = !palettePopup.visible
onClicked: {
palettePopup.visible = !palettePopup.visible
}
}
FlatButton {
id: searchTextButton
anchors.right: parent.right
objectName: "SearchPalettesBtn"
keynav.subsection: keynavSub
keynav.order: 2
enabled: !searchTextInput.visible
icon: IconCode.SEARCH
onClicked: {
toggleSearch()
}
@ -78,12 +99,47 @@ Item {
id: searchTextInput
width: parent.width
//! TODO Move to SearchField inside
KeyNavigationControl {
id: keynavSearchField
name: "SearchPalettesField"
subsection: keynavSub
order: 3
enabled: searchTextInput.visible
onActiveChanged: {
if (keynavSearchField.active) {
searchTextInput.forceActiveFocus()
}
}
}
KeyNavigationControl {
id: keynavSearchFieldClose
name: "SearchPalettesFieldClose"
subsection: keynavSub
order: 4
enabled: searchTextInput.visible && searchTextInput.clearTextButtonVisible
onTriggered: toggleSearch()
}
onVisibleChanged: {
if (!searchTextInput.visible) {
morePalettesButton.keynav.forceActive()
}
}
//! ----------
visible: false
onSearchTextChanged: resultsTimer.restart()
onActiveFocusChanged: {
resultsTimer.stop();
Accessible.name = qsTrc("palette", "Palette Search")
if (searchTextInput.activeFocus) {
keynavSearchField.forceActive()
}
}
Timer {
@ -94,10 +150,6 @@ Item {
}
}
KeyNavigation.tab: paletteTree.currentTreeItem
Keys.onDownPressed: paletteTree.focusFirstItem();
Keys.onUpPressed: paletteTree.focusLastItem();
Keys.onEscapePressed: toggleSearch()
clearTextButtonVisible: true
@ -137,12 +189,4 @@ Item {
createCustomPalettePopup.open()
}
}
Connections {
target: palettesWidget
function onHasFocusChanged() {
if (!palettesWidget.hasFocus && !palettePopup.inMenuAction)
palettePopup.visible = false;
}
}
}

View file

@ -37,6 +37,9 @@ Item {
property PaletteWorkspace paletteWorkspace
property var modelIndex: null
property KeyNavigationSubSection keynavSubsection: null
property int keynavRow: 0
signal toggleExpandRequested()
signal enableEditingToggled(bool val)
signal hideSelectedElementsRequested()
@ -66,6 +69,11 @@ Item {
icon: paletteHeader.expanded ? IconCode.SMALL_ARROW_DOWN : IconCode.SMALL_ARROW_RIGHT
normalStateColor: "transparent"
enabled: paletteExpandArrow.visible
keynav.subsection: paletteHeader.keynavSubsection
keynav.row: paletteHeader.keynavRow
keynav.column: 1
onClicked: paletteHeader.toggleExpandRequested()
}
@ -99,8 +107,10 @@ Item {
activeFocusOnTab: mainPalette.currentItem === paletteTree.currentTreeItem
normalStateColor: "transparent"
KeyNavigation.backtab: mainPalette.currentItem
KeyNavigation.tab: focusBreaker
enabled: deleteButton.visible
keynav.subsection: paletteHeader.keynavSubsection
keynav.row: paletteHeader.keynavRow
keynav.column: 2
onClicked: {
hideSelectedElementsRequested()
@ -115,7 +125,10 @@ Item {
visible: paletteHeader.expanded || paletteHeader.hovered || paletteHeaderMenu.visible
activeFocusOnTab: parent.parent.parent === paletteTree.currentTreeItem
enabled: paletteHeaderMenuButton.visible
keynav.subsection: paletteHeader.keynavSubsection
keynav.row: paletteHeader.keynavRow
keynav.column: 3
icon: IconCode.MENU_THREE_DOTS
normalStateColor: "transparent"