Welcome to mirror list, hosted at ThFree Co, Russian Federation.

ExpandableComponent.qml « qml « resources - github.com/Ultimaker/Cura.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: e5eab3bd93abd6014997d162f9060eb982d28bd4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
// 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.RecolorImage
            {
                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:
                {
                    clickPos = Qt.point(mouse.x, mouse.y);
                    dragging = true
                }

                onPositionChanged:
                {
                    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 {}

            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
        function onWidthChanged() { content.width = content.contentItem.width + 2 * content.padding }
        function onHeightChanged()
        {
            content.height = content.contentItem.height + 2 * content.padding
            contentContainer.height = contentHeader.height + content.height
        }
    }
}