TileView.qml 6.37 KB
Newer Older
1
2
import QtQuick 2.15
import QtQuick.Controls 2.15
3
import QtQml 2.15  // Binding.restoreMode
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

Control {
    id: root

    property int majorOrientation: Qt.Horizontal
    property int majorCount: 2
    property var minorCounts: [5, 5]

    property var _majorPositions: {
        let positions = [];
        for (let i = 0; i < majorCount; ++i) {
            positions.push(i / majorCount);
        }
        return positions;
    }
    property var _minorPositions: {
        let count = Math.max(...minorCounts);
        let positions = [];
        for (let i = 0; i < count; ++i) {
            positions.push(i / count);
        }
        return positions;
    }

    property alias model: contentRepeater.model
    property Component delegate

    contentItem: Item {
        id: contentArea

        Item {
            anchors.fill: parent
            Repeater {
                id: contentRepeater
                Item {
                    id: tile

                    // TODO: how to propagate required properties from delegate
                    required property int index
                    required property string name
                    required property int tileIndex

                    readonly property int majorIndex: {
                        let count = 0;
                        for (let i = 0; i < root.minorCounts.length; ++i) {
                            count += root.minorCounts[i];
                            if (tileIndex < count)
                                return i;
                        }
                        return root.minorCounts.length;
                    }
                    readonly property int minorIndex: {
                        tileIndex - root.minorCounts.slice(0, majorIndex).reduce((a, b) => a + b, 0)
                    }

                    // TODO: handle out-of-range index
                    readonly property real _majorPosition: root._majorPositions[majorIndex]
                    readonly property real _minorPosition: root._minorPositions[minorIndex]
                    readonly property real _majorSize: {
                        (majorIndex + 1 < root.majorCount ? root._majorPositions[majorIndex + 1] : 1) - _majorPosition
                    }
                    readonly property real _minorSize: {
                        let n = minorIndex < root.minorCounts.length ? root.minorCounts[minorIndex] : 0;
                        return (minorIndex + 1 < n ? root._minorPositions[minorIndex + 1] : 1) - _minorPosition;
                    }

                    x: contentArea.width * (root.majorOrientation === Qt.Horizontal ? _majorPosition : _minorPosition)
                    y: contentArea.height * (root.majorOrientation === Qt.Horizontal ? _minorPosition : _majorPosition)
                    width: contentArea.width * (root.majorOrientation === Qt.Horizontal ? _majorSize : _minorSize)
                    height: contentArea.height * (root.majorOrientation === Qt.Horizontal ? _minorSize : _majorSize)
                    visible: tileIndex >= 0 && majorIndex < root.majorCount && minorIndex < root.minorCounts[majorIndex]

                    Component.onCompleted: {
                        root.delegate.createObject(tile, {
                            name: Qt.binding(() => tile.name),
                            index: Qt.binding(() => tile.index),
                            tileIndex: Qt.binding(() => tile.tileIndex),
                        });
                    }

                    // XXX
                    Rectangle {
                        anchors.fill: parent
                        z: -1
                        border.width: 1
                        border.color: "gray"
                        color: "transparent"
                    }
                }
            }
        }
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

        Item {
            anchors.fill: parent

            Repeater {
                model: root.majorCount
                Rectangle {
                    id: majorHandle

                    required property int index

                    // TODO: race on majorOrientation changed
                    anchors.left: root.majorOrientation !== Qt.Horizontal ? parent.left : undefined
                    anchors.right: root.majorOrientation !== Qt.Horizontal ? parent.right : undefined
                    anchors.top: root.majorOrientation === Qt.Horizontal ? parent.top : undefined
                    anchors.bottom: root.majorOrientation === Qt.Horizontal ? parent.bottom : undefined
                    width: 5
                    height: 5
                    visible: index > 0
                    color: "gray"

                    onXChanged: {
                        if (root.majorOrientation !== Qt.Horizontal || !majorDragHandler.active)
                            return;
                        let positions = root._majorPositions;
                        positions[index] = x / contentArea.width;
                        root._majorPositions = positions;
                    }

                    onYChanged: {
                        if (root.majorOrientation === Qt.Horizontal || !majorDragHandler.active)
                            return;
                        let positions = root._majorPositions;
                        positions[index] = y / contentArea.height;
                        root._majorPositions = positions;
                    }

                    Binding on x {
                        when: root.majorOrientation === Qt.Horizontal && !majorDragHandler.active
                        value: contentArea.width * root._majorPositions[majorHandle.index]
                        restoreMode: Binding.RestoreNone
                    }

                    Binding on y {
                        when: root.majorOrientation !== Qt.Horizontal && !majorDragHandler.active
                        value: contentArea.height * root._majorPositions[majorHandle.index]
                        restoreMode: Binding.RestoreNone
                    }

                    HoverHandler {
                        cursorShape: root.majorOrientation === Qt.Horizontal ? Qt.SplitHCursor : Qt.SplitVCursor
                    }

                    DragHandler {
                        id: majorDragHandler
                        xAxis.enabled: root.majorOrientation === Qt.Horizontal
                        yAxis.enabled: root.majorOrientation !== Qt.Horizontal
                        // TODO: minimum/maximum
                    }
                }
            }
        }
157
158
    }
}