Implemented menu for window in Linux
This commit is contained in:
parent
f4a4401538
commit
bb1bc46df0
10 changed files with 158 additions and 136 deletions
|
@ -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>
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ import MuseScore.Ui 1.0
|
|||
import MuseScore.UiComponents 1.0
|
||||
import MuseScore.AppShell 1.0
|
||||
|
||||
import "../../"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue