mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-04-23 14:19:37 +08:00
321 lines
11 KiB
QML
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
|
|
}
|
|
}
|
|
}
|