Browse Source

Merge pull request #13975 from Ultimaker/CURA-9622_unable_to_scroll_long_materials_list

[CURA-9522] Materials list goes off screen.
Remco Burema 2 years ago
parent
commit
0cdfa3477b

+ 6 - 0
resources/qml/Cura.qml

@@ -17,6 +17,12 @@ UM.MainWindow
 {
     id: base
 
+    Item
+    {
+        id: mainWindow
+        anchors.fill: parent
+    }
+
     // Cura application window title
     title:
     {

+ 39 - 79
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;
-                                        }
-                                    }
                                 }
                             }
                         }

+ 118 - 0
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")
+        }
+    }
+}