Cura/resources/qml/ExpandableComponent.qml
Jaime van Kessel 965ecb744d Fix size of print setup selector
CURA-9139
2022-04-19 16:42:43 +02:00

321 lines
11 KiB
QML

// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.3
import UM 1.5 as UM
import Cura 1.0 as Cura
// The expandable component has 2 major sub components:
// * The headerItem; Always visible and should hold some info about what happens if the component is expanded
// * The contentItem; The content that needs to be shown if the component is expanded.
Item
{
id: base
// Enumeration with the different possible alignments of the content with respect of the headerItem
enum ContentAlignment
{
AlignLeft,
AlignRight
}
// The headerItem holds the QML item that is always displayed.
property alias headerItem: headerItemLoader.sourceComponent
// The contentItem holds the QML item that is shown when the "open" button is pressed
property alias contentItem: content.contentItem
property color contentBackgroundColor: UM.Theme.getColor("action_button")
property color headerBackgroundColor: UM.Theme.getColor("action_button")
property color headerActiveColor: UM.Theme.getColor("expandable_active")
property color headerHoverColor: UM.Theme.getColor("expandable_hover")
property alias enabled: mouseArea.enabled
// Text to show when this component is disabled
property alias disabledText: disabledLabel.text
// Defines the alignment of the content with respect of the headerItem, by default to the right
// Note that this only has an effect if the panel is draggable
property int contentAlignment: ExpandableComponent.ContentAlignment.AlignRight
// How much spacing is needed around the contentItem
property alias contentPadding: content.padding
// Adds a title to the content item
property alias contentHeaderTitle: contentHeader.headerTitle
// How much spacing is needed for the contentItem by Y coordinate
property var contentSpacingY: UM.Theme.getSize("narrow_margin").width
// How much padding is needed around the header & button
property alias headerPadding: background.padding
property alias headerBackgroundBorder: background.border
// Whether or not to show the background border
property bool enableHeaderBackgroundBorder: true
// What icon should be displayed on the right.
property alias iconSource: collapseButton.source
property alias iconColor: collapseButton.color
// The icon size (it's always drawn as a square)
property alias iconSize: collapseButton.height
// Is the "drawer" open?
property alias expanded: contentContainer.visible
// What should the radius of the header be. This is also influenced by the headerCornerSide
property alias headerRadius: background.radius
// On what side should the header corners be shown? 1 is down, 2 is left, 3 is up and 4 is right.
property alias headerCornerSide: background.cornerSide
// Distance between the header and the content.
property int popupOffset: 2 * UM.Theme.getSize("default_lining").height
// Prefix used for the dragged position preferences. Preferences not used if empty. Don't translate!
property string dragPreferencesNamePrefix: ""
function toggleContent()
{
contentContainer.visible = !expanded
}
function updateDragPosition()
{
contentContainer.trySetPosition(contentContainer.x, contentContainer.y);
}
onEnabledChanged:
{
if (!base.enabled && expanded)
{
toggleContent();
updateDragPosition();
}
}
// Add this binding since the background color is not updated otherwise
Binding
{
target: background
property: "color"
value:
{
return base.enabled ? (expanded ? headerActiveColor : headerBackgroundColor) : UM.Theme.getColor("disabled")
}
}
implicitHeight: 100 * screenScaleFactor
implicitWidth: 400 * screenScaleFactor
RoundedRectangle
{
id: background
property real padding: UM.Theme.getSize("default_margin").width
border.width: base.enableHeaderBackgroundBorder ? UM.Theme.getSize("default_lining").width : 0
border.color: UM.Theme.getColor("lining")
color: base.enabled ? (base.expanded ? headerActiveColor : headerBackgroundColor) : UM.Theme.getColor("disabled")
anchors.fill: parent
UM.Label
{
id: disabledLabel
visible: !base.enabled
anchors.fill: parent
leftPadding: background.padding
rightPadding: background.padding
text: ""
wrapMode: Text.WordWrap
}
Item
{
anchors.fill: parent
visible: base.enabled
Loader
{
id: headerItemLoader
anchors
{
left: parent.left
right: collapseButton.visible ? collapseButton.left : parent.right
top: parent.top
bottom: parent.bottom
margins: background.padding
}
}
UM.ColorImage
{
id: collapseButton
anchors
{
right: parent.right
verticalCenter: parent.verticalCenter
margins: background.padding
}
source: UM.Theme.getIcon("ChevronSingleDown")
visible: source != ""
width: UM.Theme.getSize("standard_arrow").width
height: UM.Theme.getSize("standard_arrow").height
color: UM.Theme.getColor("small_button_text")
}
}
MouseArea
{
id: mouseArea
anchors.fill: parent
onClicked: toggleContent()
hoverEnabled: true
onEntered: background.color = headerHoverColor
onExited: background.color = base.enabled ? (base.expanded ? headerActiveColor : headerBackgroundColor) : UM.Theme.getColor("disabled")
}
}
Cura.RoundedRectangle
{
id: contentContainer
property string dragPreferencesNameX: "_xpos"
property string dragPreferencesNameY: "_ypos"
visible: false
width: childrenRect.width
height: childrenRect.height
// Ensure that the content is located directly below the headerItem
y: dragPreferencesNamePrefix === "" ? (background.height + base.popupOffset + base.contentSpacingY) : UM.Preferences.getValue(dragPreferencesNamePrefix + dragPreferencesNameY)
// Make the content aligned with the rest, using the property contentAlignment to decide whether is right or left.
// In case of right alignment, the 3x padding is due to left, right and padding between the button & text.
x: dragPreferencesNamePrefix === "" ? (contentAlignment == ExpandableComponent.ContentAlignment.AlignRight ? -width + collapseButton.width + headerItemLoader.width + 3 * background.padding : 0) : UM.Preferences.getValue(dragPreferencesNamePrefix + dragPreferencesNameX)
cornerSide: Cura.RoundedRectangle.Direction.All
color: contentBackgroundColor
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
radius: UM.Theme.getSize("default_radius").width
function trySetPosition(posNewX, posNewY)
{
var margin = UM.Theme.getSize("narrow_margin");
var minPt = base.mapFromItem(null, margin.width, margin.height);
var maxPt = base.mapFromItem(null,
CuraApplication.appWidth() - (contentContainer.width + margin.width),
CuraApplication.appHeight() - (contentContainer.height + margin.height));
var initialY = background.height + base.popupOffset + margin.height;
contentContainer.x = Math.max(minPt.x, Math.min(maxPt.x, posNewX));
contentContainer.y = Math.max(initialY, Math.min(maxPt.y, posNewY));
if (dragPreferencesNamePrefix !== "")
{
UM.Preferences.setValue(dragPreferencesNamePrefix + dragPreferencesNameX, contentContainer.x);
UM.Preferences.setValue(dragPreferencesNamePrefix + dragPreferencesNameY, contentContainer.y);
}
}
ExpandableComponentHeader
{
id: contentHeader
headerTitle: ""
anchors
{
top: parent.top
right: parent.right
left: parent.left
}
MouseArea
{
id: dragRegion
cursorShape: Qt.SizeAllCursor
anchors
{
top: parent.top
bottom: parent.bottom
left: parent.left
right: contentHeader.xPosCloseButton
}
property var clickPos: Qt.point(0, 0)
property bool dragging: false
onPressed: (mouse) =>
{
clickPos = Qt.point(mouse.x, mouse.y);
dragging = true
}
onPositionChanged: (mouse) =>
{
if(dragging)
{
var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y);
if (delta.x !== 0 || delta.y !== 0)
{
contentContainer.trySetPosition(contentContainer.x + delta.x, contentContainer.y + delta.y);
}
}
}
onReleased: dragging = false
onDoubleClicked:
{
dragging = false
contentContainer.trySetPosition(0, 0);
}
Connections
{
target: UM.Preferences
function onPreferenceChanged(preference)
{
if
(
preference !== "general/window_height" &&
preference !== "general/window_width" &&
preference !== "general/window_state"
)
{
return;
}
contentContainer.trySetPosition(contentContainer.x, contentContainer.y);
}
}
}
}
Control
{
id: content
anchors.top: contentHeader.bottom
padding: UM.Theme.getSize("default_margin").width
contentItem: Item {}
}
}
// DO NOT MOVE UP IN THE CODE: This connection has to be here, after the definition of the content item.
// Apparently the order in which these are handled matters and so the height is correctly updated if this is here.
Connections
{
// Since it could be that the content is dynamically populated, we should also take these changes into account.
target: content.contentItem
function onHeightChanged()
{
contentContainer.height = contentHeader.height + content.height
}
}
}