Implemented menu for window in Linux

This commit is contained in:
Eism 2021-11-01 16:45:44 +02:00
parent f4a4401538
commit bb1bc46df0
10 changed files with 158 additions and 136 deletions

View file

@ -69,11 +69,8 @@
<file>qml/dockwindow/DockPanel.qml</file>
<file>qml/dockwindow/DropIndicators.qml</file>
<file>qml/dockwindow/DropIndicator.qml</file>
<file>qml/AppTitleBar.qml</file>
<file>qml/AppWindow.qml</file>
<file>qml/WindowContent.qml</file>
<file>qml/AppMenuBar.qml</file>
<file>qml/platform/linux/AppTitleBarLinux.qml</file>
<file>qml/platform/linux/Main.qml</file>
<file>qml/platform/mac/Main.qml</file>
<file>qml/platform/win/Main.qml</file>
@ -94,5 +91,7 @@
<file>qml/Preferences/internal/DefaultFilesSection.qml</file>
<file>qml/Preferences/internal/ScoreViewSection.qml</file>
<file>qml/Preferences/internal/AutomaticUpdateSection.qml</file>
<file>qml/platform/win/AppTitleBar.qml</file>
<file>qml/AppMenuBar.qml</file>
</qresource>
</RCC>

View file

@ -1,49 +0,0 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore BVBA and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import QtQuick 2.15
import "../../"
AppTitleBar {
id: root
signal startSystemMoveRequested()
TapHandler {
readonly property int maximizeTapCount: 2
gesturePolicy: TapHandler.DragThreshold
onTapped: {
if (tapCount === maximizeTapCount) {
root.toggleWindowMaximizedRequested()
}
}
}
DragHandler {
grabPermissions: TapHandler.CanTakeOverFromAnything
onActiveChanged: {
if (active) {
root.startSystemMoveRequested()
}
}
}
}

View file

@ -21,6 +21,7 @@
*/
import QtQuick 2.15
import MuseScore.Ui 1.0
import MuseScore.UiComponents 1.0
import "../../"
@ -28,9 +29,34 @@ import "../../"
AppWindow {
id: root
AppMenuBar {
id: appMenuBar
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
navigation.section: navSec
NavigationSection {
id: navSec
name: "AppMenuBar"
order: 0
onActiveChanged: {
if (active) {
appMenuBar.forceActiveFocus()
}
}
}
}
WindowContent {
id: window
anchors.fill: parent
anchors.top: appMenuBar.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
}
}

View file

@ -25,6 +25,8 @@ import MuseScore.Ui 1.0
import MuseScore.UiComponents 1.0
import MuseScore.AppShell 1.0
import "../../"
Rectangle {
id: root

View file

@ -0,0 +1,103 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore BVBA and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import QtQml 2.15
import MuseScore.Ui 1.0
import MuseScore.UiComponents 1.0
QtObject {
id: root
property bool hasItemsWithIconAndCheckable: false
property bool hasItemsWithIconOrCheckable: false
property bool hasItemsWithSubmenu: false
property bool hasItemsWithShortcut: false
property int itemLeftPartWidth: 100
property int itemRightPartWidth: 100
property int minimumMenuWidth: 178
readonly property int itemWidth:
Math.max(itemLeftPartWidth + itemRightPartWidth, minimumMenuWidth)
property int iconAndCheckMarkMode: {
if (hasItemsWithIconAndCheckable) {
return StyledMenuItem.ShowBoth
} else if (hasItemsWithIconOrCheckable) {
return StyledMenuItem.ShowOne
}
return StyledMenuItem.None
}
function calculate(model) {
root.hasItemsWithIconAndCheckable = false
root.hasItemsWithIconOrCheckable = false
root.hasItemsWithSubmenu = false
root.hasItemsWithShortcut = false
//! NOTE Policy:
//! - if the menu contains checkable items, space for the checkmarks is reserved
//! - if the menu contains items with an icon, space for icons is reserved
//! - selectable items that don't have an icon are treated as checkable
//! - selectable items that do have an icon are treated as non-checkable
//! - all selectable items that are selected get an accent color background
for (let i = 0; i < model.length; i++) {
let item = Utils.getItem(model,i)
let hasIcon = (Boolean(item.icon) && item.icon !== IconCode.NONE)
if (item.checkable && hasIcon) {
root.hasItemsWithIconAndCheckable = true
root.hasItemsWithIconOrCheckable = true
} else if (item.checkable || hasIcon || item.selectable) {
root.hasItemsWithIconOrCheckable = true
}
if (Boolean(item.subitems) && item.subitems.length > 0) {
root.hasItemsWithSubmenu = true
}
if (Boolean(item.shortcut)) {
root.hasItemsWithShortcut = true
}
}
let leftWidth = 0
let rightWidth = 0
for (let j = 0; j < model.length; j++) {
testItem.modelData = Utils.getItem(model, j)
leftWidth = Math.max(leftWidth, testItem.calculatedLeftPartWidth())
rightWidth = Math.max(rightWidth, testItem.calculatedRightPartWidth())
}
root.itemLeftPartWidth = leftWidth
root.itemRightPartWidth = rightWidth
}
property StyledMenuItem testItem: StyledMenuItem {
iconAndCheckMarkMode: root.iconAndCheckMarkMode
reserveSpaceForShortcutOrSubmenuIndicator:
root.hasItemsWithShortcut || root.hasItemsWithSubmenu
}
}

View file

@ -30,7 +30,6 @@ StyledPopupView {
id: root
property alias model: view.model
property int minimumMenuWidth: 178
property int preferredAlign: Qt.AlignRight // Left, HCenter, Right
@ -51,7 +50,7 @@ StyledPopupView {
y: parent.height
contentWidth: prv.itemWidth
contentWidth: menuMetrics.itemWidth
padding: 8
margins: 0
@ -90,49 +89,7 @@ StyledPopupView {
}
onModelChanged: {
prv.hasItemsWithIconAndCheckable = false
prv.hasItemsWithIconOrCheckable = false
prv.hasItemsWithSubmenu = false
prv.hasItemsWithShortcut = false
//! NOTE Policy:
//! - if the menu contains checkable items, space for the checkmarks is reserved
//! - if the menu contains items with an icon, space for icons is reserved
//! - selectable items that don't have an icon are treated as checkable
//! - selectable items that do have an icon are treated as non-checkable
//! - all selectable items that are selected get an accent color background
for (let i = 0; i < model.length; i++) {
let item = prv.getItem(i)
let hasIcon = (Boolean(item.icon) && item.icon !== IconCode.NONE)
if (item.checkable && hasIcon) {
prv.hasItemsWithIconAndCheckable = true
prv.hasItemsWithIconOrCheckable = true
} else if (item.checkable || hasIcon || item.selectable) {
prv.hasItemsWithIconOrCheckable = true
}
if (Boolean(item.subitems) && item.subitems.length > 0) {
prv.hasItemsWithSubmenu = true
}
if (Boolean(item.shortcut)) {
prv.hasItemsWithShortcut = true
}
}
let leftWidth = 0
let rightWidth = 0
for (let j = 0; j < model.length; j++) {
prv.testItem.modelData = prv.getItem(j)
leftWidth = Math.max(leftWidth, prv.testItem.calculatedLeftPartWidth())
rightWidth = Math.max(rightWidth, prv.testItem.calculatedRightPartWidth())
}
prv.itemLeftPartWidth = leftWidth
prv.itemRightPartWidth = rightWidth
menuMetrics.calculate(model)
//! NOTE: Due to the fact that the view has a dynamic delegate,
// the height calculation occurs with an error
@ -140,7 +97,7 @@ StyledPopupView {
// Let's manually adjust the height of the content
var sepCount = 0
for (let k = 0; k < model.length; k++) {
if (!Boolean(prv.getItem(k).title)) {
if (!Boolean(Utils.getItem(model, k).title)) {
sepCount++
}
}
@ -158,40 +115,18 @@ StyledPopupView {
root.loaded()
}
MenuMetrics {
id: menuMetrics
}
QtObject {
id: prv
property var showedSubMenu: null
property bool hasItemsWithIconAndCheckable: false
property bool hasItemsWithIconOrCheckable: false
property bool hasItemsWithSubmenu: false
property bool hasItemsWithShortcut: false
property int itemLeftPartWidth: 100
property int itemRightPartWidth: 100
readonly property int itemWidth:
Math.max(itemLeftPartWidth + itemRightPartWidth, root.minimumMenuWidth)
readonly property int separatorHeight: 1
readonly property int viewVerticalMargin: 4
property int iconAndCheckMarkMode: {
if (prv.hasItemsWithIconAndCheckable) {
return StyledMenuItem.ShowBoth
} else if (prv.hasItemsWithIconOrCheckable) {
return StyledMenuItem.ShowOne
}
return StyledMenuItem.None
}
property StyledMenuItem testItem: StyledMenuItem {
iconAndCheckMarkMode: prv.iconAndCheckMarkMode
reserveSpaceForShortcutOrSubmenuIndicator:
prv.hasItemsWithShortcut || prv.hasItemsWithSubmenu
}
function focusOnFirstEnabled() {
for (var i = 0; i < view.count; ++i) {
var loader = view.itemAtIndex(i)
@ -214,14 +149,6 @@ StyledPopupView {
}
return false
}
function getItem(row) {
if (Boolean(root.model.get)) {
return root.model.get(row)
}
return root.model[row]
}
}
ListView {
@ -244,7 +171,7 @@ StyledPopupView {
onLoaded: {
loader.item.modelData = Qt.binding(() => (itemData))
loader.item.width = Qt.binding(() => (prv.itemWidth))
loader.item.width = Qt.binding(() => (menuMetrics.itemWidth))
}
Component {
@ -256,10 +183,10 @@ StyledPopupView {
navigation.panel: root.navigationPanel
navigation.row: model.index
iconAndCheckMarkMode: prv.iconAndCheckMarkMode
iconAndCheckMarkMode: menuMetrics.iconAndCheckMarkMode
reserveSpaceForShortcutOrSubmenuIndicator:
prv.hasItemsWithShortcut || prv.hasItemsWithSubmenu
menuMetrics.hasItemsWithShortcut || menuMetrics.hasItemsWithSubmenu
padding: root.padding

View file

@ -282,6 +282,10 @@ ListItemBlank {
if (isHovered) {
itemPrv.showSubMenu()
} else {
if (!Boolean(itemPrv.showedSubMenu)) {
return
}
var mouseGlogalPos = mapToGlobal(Qt.point(mouseX, mouseY))
var showedSubMenuGlobalPos = itemPrv.showedSubMenu.contentItem.mapToGlobal(0, 0)

View file

@ -52,3 +52,11 @@ function ensureContentVisible(flickable, contentRect, margins) {
flickable.contentY -= flicableTopY - contentTopY + margins
}
}
function getItem(model, row) {
if (Boolean(model.get)) {
return model.get(row)
}
return model[row]
}

View file

@ -46,4 +46,5 @@ FilePicker 1.0 FilePicker.qml
ValueList 1.0 ValueList.qml
StyledDropShadow 1.0 StyledDropShadow.qml
VisibilityBox 1.0 VisibilityBox.qml
MenuMetrics 1.0 MenuMetrics.qml
Utils 1.0 Utils.js

View file

@ -55,5 +55,6 @@
<file>qml/MuseScore/UiComponents/Dropdown.qml</file>
<file>qml/MuseScore/UiComponents/internal/DropdownItem.qml</file>
<file>qml/MuseScore/UiComponents/VisibilityBox.qml</file>
<file>qml/MuseScore/UiComponents/MenuMetrics.qml</file>
</qresource>
</RCC>