|
@@ -0,0 +1,204 @@
|
|
|
+import QtQuick 2.7
|
|
|
+import QtQuick.Controls 2.3
|
|
|
+
|
|
|
+import UM 1.2 as UM
|
|
|
+import Cura 1.0 as Cura
|
|
|
+
|
|
|
+import QtGraphicalEffects 1.0 // For the dropshadow
|
|
|
+
|
|
|
+// 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("secondary")
|
|
|
+ property color headerHoverColor: UM.Theme.getColor("action_button_hovered")
|
|
|
+
|
|
|
+ // Defines the alignment of the content with respect of the headerItem, by default to the right
|
|
|
+ property int contentAlignment: ExpandablePopup.ContentAlignment.AlignRight
|
|
|
+
|
|
|
+ // How much spacing is needed around the contentItem
|
|
|
+ property alias contentPadding: content.padding
|
|
|
+
|
|
|
+ // How much padding is needed around the header & button
|
|
|
+ property alias headerPadding: background.padding
|
|
|
+
|
|
|
+ // 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?
|
|
|
+ readonly property alias expanded: content.visible
|
|
|
+
|
|
|
+ property alias expandedHighlightColor: expandedHighlight.color
|
|
|
+
|
|
|
+ // 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
|
|
|
+
|
|
|
+ // Change the contentItem close behaviour
|
|
|
+ property alias contentClosePolicy : content.closePolicy
|
|
|
+
|
|
|
+ property alias headerShadowColor: shadow.color
|
|
|
+
|
|
|
+ property alias enableHeaderShadow: shadow.visible
|
|
|
+
|
|
|
+ property int shadowOffset: 2
|
|
|
+
|
|
|
+ function toggleContent()
|
|
|
+ {
|
|
|
+ if (content.visible)
|
|
|
+ {
|
|
|
+ content.close()
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ content.open()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ implicitHeight: 100 * screenScaleFactor
|
|
|
+ implicitWidth: 400 * screenScaleFactor
|
|
|
+
|
|
|
+ RoundedRectangle
|
|
|
+ {
|
|
|
+ id: background
|
|
|
+ property real padding: UM.Theme.getSize("default_margin").width
|
|
|
+
|
|
|
+ color: headerBackgroundColor
|
|
|
+ anchors.fill: parent
|
|
|
+
|
|
|
+ Loader
|
|
|
+ {
|
|
|
+ id: headerItemLoader
|
|
|
+ anchors
|
|
|
+ {
|
|
|
+ left: parent.left
|
|
|
+ right: collapseButton.visible ? collapseButton.left : parent.right
|
|
|
+ top: parent.top
|
|
|
+ bottom: parent.bottom
|
|
|
+ margins: background.padding
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // A highlight that is shown when the content is expanded
|
|
|
+ Rectangle
|
|
|
+ {
|
|
|
+ id: expandedHighlight
|
|
|
+ width: parent.width
|
|
|
+ height: UM.Theme.getSize("thick_lining").height
|
|
|
+ color: UM.Theme.getColor("primary")
|
|
|
+ visible: expanded
|
|
|
+ anchors.bottom: parent.bottom
|
|
|
+ }
|
|
|
+
|
|
|
+ UM.RecolorImage
|
|
|
+ {
|
|
|
+ id: collapseButton
|
|
|
+ anchors
|
|
|
+ {
|
|
|
+ right: parent.right
|
|
|
+ verticalCenter: parent.verticalCenter
|
|
|
+ margins: background.padding
|
|
|
+ }
|
|
|
+ sourceSize.width: width
|
|
|
+ sourceSize.height: height
|
|
|
+ source: expanded ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left")
|
|
|
+ visible: source != ""
|
|
|
+ width: UM.Theme.getSize("standard_arrow").width
|
|
|
+ height: UM.Theme.getSize("standard_arrow").height
|
|
|
+ color: UM.Theme.getColor("text")
|
|
|
+ }
|
|
|
+
|
|
|
+ MouseArea
|
|
|
+ {
|
|
|
+ id: mouseArea
|
|
|
+ anchors.fill: parent
|
|
|
+ onClicked: toggleContent()
|
|
|
+ hoverEnabled: true
|
|
|
+ onEntered: background.color = headerHoverColor
|
|
|
+ onExited: background.color = headerBackgroundColor
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ DropShadow
|
|
|
+ {
|
|
|
+ id: shadow
|
|
|
+ // Don't blur the shadow
|
|
|
+ radius: 0
|
|
|
+ anchors.fill: background
|
|
|
+ source: background
|
|
|
+ verticalOffset: base.shadowOffset
|
|
|
+ visible: true
|
|
|
+ color: UM.Theme.getColor("action_button_shadow")
|
|
|
+ // Should always be drawn behind the background.
|
|
|
+ z: background.z - 1
|
|
|
+ }
|
|
|
+
|
|
|
+ Popup
|
|
|
+ {
|
|
|
+ id: content
|
|
|
+
|
|
|
+ // Ensure that the content is located directly below the headerItem
|
|
|
+ y: background.height + base.shadowOffset
|
|
|
+
|
|
|
+ // 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: contentAlignment == ExpandablePopup.ContentAlignment.AlignRight ? -width + collapseButton.width + headerItemLoader.width + 3 * background.padding : 0
|
|
|
+ padding: UM.Theme.getSize("default_margin").width
|
|
|
+ closePolicy: Popup.CloseOnPressOutsideParent
|
|
|
+
|
|
|
+ background: Cura.RoundedRectangle
|
|
|
+ {
|
|
|
+ cornerSide: Cura.RoundedRectangle.Direction.Down
|
|
|
+ color: contentBackgroundColor
|
|
|
+ border.width: UM.Theme.getSize("default_lining").width
|
|
|
+ border.color: UM.Theme.getColor("lining")
|
|
|
+ radius: UM.Theme.getSize("default_radius").width
|
|
|
+ }
|
|
|
+
|
|
|
+ contentItem: Item {}
|
|
|
+
|
|
|
+ onContentItemChanged:
|
|
|
+ {
|
|
|
+ // Since we want the size of the content to be set by the size of the content,
|
|
|
+ // we need to do it like this.
|
|
|
+ content.width = contentItem.width + 2 * content.padding
|
|
|
+ content.height = contentItem.height + 2 * content.padding
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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
|
|
|
+ onWidthChanged: content.width = content.contentItem.width + 2 * content.padding
|
|
|
+ onHeightChanged: content.height = content.contentItem.height + 2 * content.padding
|
|
|
+ }
|
|
|
+}
|