diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 6e36587b23..669fd1041e 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -17,6 +17,12 @@ UM.MainWindow { id: base + Item + { + id: mainWindow + anchors.fill: parent + } + // Cura application window title title: { diff --git a/resources/qml/Menus/MaterialBrandMenu.qml b/resources/qml/Menus/MaterialBrandMenu.qml index e256e75904..83a6959183 100644 --- a/resources/qml/Menus/MaterialBrandMenu.qml +++ b/resources/qml/Menus/MaterialBrandMenu.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2022 UltiMaker // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 @@ -36,6 +36,7 @@ Cura.MenuItem UM.Label { + id: brandLabelText text: replaceText(materialBrandMenu.text) Layout.fillWidth: true Layout.fillHeight:true @@ -84,33 +85,15 @@ Cura.MenuItem onTriggered: menuPopup.close() } - Popup + MaterialBrandSubMenu { id: menuPopup - width: materialTypesList.width + padding * 2 - height: materialTypesList.height + padding * 2 - property var flipped: false - - x: parent.width - UM.Theme.getSize("default_lining").width - y: { - // Checks if popup is more than halfway down the screen AND further than 400 down (this avoids popup going off the top of screen) - // If it is then the popup will push up instead of down - // This fixes the popups appearing bellow the bottom of the screen. - - if (materialBrandMenu.parent.height / 2 < parent.y && parent.y > 400) { - flipped = true - return -UM.Theme.getSize("default_lining").width - height + UM.Theme.getSize("menu").height - } - flipped = false - return -UM.Theme.getSize("default_lining").width - } - - padding: background.border.width // Nasty hack to ensure that we can keep track if the popup contains the mouse. // Since we also want a hover for the sub items (and these events are sent async) // We have to keep a count of itemHovered (instead of just a bool) property int itemHovered: 0 + MouseArea { id: submenuArea @@ -120,16 +103,11 @@ Cura.MenuItem onEntered: hideTimer.restartTimer() } - background: Rectangle - { - color: UM.Theme.getColor("main_background") - border.color: UM.Theme.getColor("lining") - border.width: UM.Theme.getSize("default_lining").width - } - Column { id: materialTypesList + width: UM.Theme.getSize("menu").width + height: childrenRect.height spacing: 0 property var brandMaterials: materialTypesModel.material_types @@ -146,9 +124,7 @@ Cura.MenuItem height: UM.Theme.getSize("menu").height width: UM.Theme.getSize("menu").width - color: materialTypeButton.containsMouse ? UM.Theme.getColor("background_2") : UM.Theme.getColor("background_1") - - property var isFlipped: menuPopup.flipped + color: materialTypeButton.containsMouse ? UM.Theme.getColor("background_2") : "transparent" RowLayout { @@ -185,7 +161,7 @@ Cura.MenuItem source: UM.Theme.getIcon("ChevronSingleRight") } - Item + Item { // Right side margin width: UM.Theme.getSize("default_margin").width @@ -236,34 +212,17 @@ Cura.MenuItem onTriggered: colorPopup.close() } - Popup + MaterialBrandSubMenu { id: colorPopup - width: materialColorsList.width + padding * 2 - height: materialColorsList.height + padding * 2 - x: parent.width - y: { - // If flipped the popup should push up rather than down from the parent - if (brandMaterialBase.isFlipped) { - return -height + UM.Theme.getSize("menu").height + UM.Theme.getSize("default_lining").width - } - return -UM.Theme.getSize("default_lining").width - } - property int itemHovered: 0 - padding: background.border.width - - background: Rectangle - { - color: UM.Theme.getColor("main_background") - border.color: UM.Theme.getColor("lining") - border.width: UM.Theme.getSize("default_lining").width - } Column { id: materialColorsList property var brandColors: model.colors + width: UM.Theme.getSize("menu").width + height: childrenRect.height spacing: 0 Repeater @@ -273,12 +232,38 @@ Cura.MenuItem delegate: Rectangle { height: UM.Theme.getSize("menu").height - width: UM.Theme.getSize("menu").width + width: parent.width - color: materialColorButton.containsMouse ? UM.Theme.getColor("background_2") : UM.Theme.getColor("background_1") + color: materialColorButton.containsMouse ? UM.Theme.getColor("background_2") : UM.Theme.getColor("main_background") + + MouseArea + { + id: materialColorButton + anchors.fill: parent + hoverEnabled: true + onClicked: + { + Cura.MachineManager.setMaterial(extruderIndex, model.container_node); + menuPopup.close(); + colorPopup.close(); + materialMenu.close(); + } + onEntered: + { + menuPopup.itemHovered += 1; + colorPopup.itemHovered += 1; + } + onExited: + { + menuPopup.itemHovered -= 1; + colorPopup.itemHovered -= 1; + } + } Item { + height: parent.height + width: parent.width opacity: materialBrandMenu.enabled ? 1 : 0.5 anchors.fill: parent @@ -309,31 +294,6 @@ Cura.MenuItem wrapMode: Text.NoWrap } } - - MouseArea - { - id: materialColorButton - anchors.fill: parent - - hoverEnabled: true - onClicked: - { - Cura.MachineManager.setMaterial(extruderIndex, model.container_node); - menuPopup.close(); - colorPopup.close(); - materialMenu.close(); - } - onEntered: - { - menuPopup.itemHovered += 1; - colorPopup.itemHovered += 1; - } - onExited: - { - menuPopup.itemHovered -= 1; - colorPopup.itemHovered -= 1; - } - } } } } diff --git a/resources/qml/Menus/MaterialBrandSubMenu.qml b/resources/qml/Menus/MaterialBrandSubMenu.qml new file mode 100644 index 0000000000..af7e6cfb0e --- /dev/null +++ b/resources/qml/Menus/MaterialBrandSubMenu.qml @@ -0,0 +1,118 @@ +// Copyright (c) 2022 UltiMaker +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 2.7 + +import UM 1.5 as UM +import Cura 1.7 as Cura + +Popup +{ + id: materialBrandSubMenu + + bottomPadding: UM.Theme.getSize("thin_margin").height + topPadding: UM.Theme.getSize("thin_margin").height + + implicitWidth: scrollViewContent.width + scrollbar.width + leftPadding + rightPadding + implicitHeight: scrollViewContent.height + bottomPadding + topPadding + + // offset position relative to the parent + property int implicitX: parent.width + property int implicitY: -UM.Theme.getSize("thin_margin").height + + default property alias contents: scrollViewContent.children + + x: implicitX + y: implicitY + + // needed for the `mapToItem` function to work; apparently a Popup is not an Item + Item + { + id: materialBrandSubMenuItem + anchors.fill: parent + } + + onOpened: + { + // we want to make sure here that the popup never goes out side the window so we adjust the x and y position + // based on the width/height of the mainWindow/popup. QML is a bit weird here though, as the globalPosition + // is in absolute coordinates relative to the origin of the mainWindow while setting the x and y coordinates + // of the popup only changes the position relative to the parent. + + // reset position, the remainder of the function asumes this position and size + materialBrandSubMenu.x = implicitX; + materialBrandSubMenu.y = implicitY; + materialBrandSubMenu.width = implicitWidth; + materialBrandSubMenu.height = implicitHeight; + + const globalPosition = materialBrandSubMenuItem.mapToItem(null, 0, 0); + + if (globalPosition.y > mainWindow.height - materialBrandSubMenu.height) + { + if (mainWindow.height > materialBrandSubMenu.height) + { + const targetY = mainWindow.height - materialBrandSubMenu.height; + const deltaY = globalPosition.y - targetY; + materialBrandSubMenu.y = implicitY - deltaY; + } + else + { + // if popup is taller then the the component, limit + // the components height and set the position to + // y = 0 (in absolute coordinates) + materialBrandSubMenu.y = implicitY - globalPosition.y; + materialBrandSubMenu.height = mainWindow.height; + } + } + + if (globalPosition.x > mainWindow.width - materialBrandSubMenu.width) + { + if (mainWindow.width > materialBrandSubMenu.width) + { + const targetX = mainWindow.width - materialBrandSubMenu.width; + const deltaX = globalPosition.x - targetX; + materialBrandSubMenu.x = implicitX - deltaX; + } + else + { + materialBrandSubMenu.x = implicitX - globalPosition.x; + materialBrandSubMenu.width = mainWindow.width; + } + } + } + + padding: background.border.width + + background: Rectangle + { + color: UM.Theme.getColor("main_background") + border.color: UM.Theme.getColor("lining") + border.width: UM.Theme.getSize("default_lining").width + } + + ScrollView + { + id: scrollView + anchors.fill: parent + contentHeight: scrollViewContent.height + clip: true + + ScrollBar.vertical: UM.ScrollBar + { + id: scrollbar + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + + Rectangle + { + id: scrollViewContent + width: childrenRect.width + height: childrenRect.height + color: UM.Theme.getColor("main_background") + } + } +} \ No newline at end of file