File: DynamicSplitView.qml

package info (click to toggle)
vtk9 9.5.2%2Bdfsg3-4
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 205,916 kB
  • sloc: cpp: 2,336,565; ansic: 327,116; python: 111,200; yacc: 4,104; java: 3,977; sh: 3,032; xml: 2,771; perl: 2,189; lex: 1,787; makefile: 178; javascript: 165; objc: 153; tcl: 59
file content (229 lines) | stat: -rw-r--r-- 6,604 bytes parent folder | download | duplicates (6)
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
import QtQuick 2.15
import QtQuick.Controls 2.15

Item {
  id: root
  objectName: "DynamicSplitView_root"

  property Component itemDelegate: null

  component ItemDelegate : Item {
    objectName: "<constructing ItemDelegate>"

    property int myIID: 0
    property var mySplitBase: this
    property var mySplitView: SplitView.view

    anchors.fill: mySplitView ? null : parent

    SplitView.preferredWidth: mySplitView
                  ? mySplitView.orientation === Qt.Horizontal
                    ? mySplitView.width / mySplitView.count
                    : mySplitView.width
                  : 0

    SplitView.preferredHeight: mySplitView
                  ? mySplitView.orientation === Qt.Vertical
                    ? mySplitView.height / mySplitView.count
                    : mySplitView.height
                  : 0

    function split(orientation) {
      if (mySplitView)
        mySplitView.split(this, orientation)
      else
        console.warn("YIKES!! DynamicSplitView.ItemDelegate.split() called when this item is NOT inside a QML SplitView")
    }

    function unsplit() {
      if (mySplitView)
        mySplitView.unsplit(this)
      else
        console.warn("YIKES!! DynamicSplitView.ItemDelegate.unsplit() called when this item is NOT inside a QML SplitView")
    }

    Component.onDestruction: {
      console.log("destructed", this, mySplitView)
    }
  }

  QtObject {
    id: d

    property int splitItemCount: 0
    property int splitViewCount: 0
    property var topSplitView: null
    property Component splitViewComponent: ItemDelegate
    {
      SplitView {
        anchors.fill: parent

        objectName: "<constructing SplitView>"

        function __indexOf(item)
        {
          // Find the item's index
          for (var index=0; index<count; ++index)
            if (itemAt(index) === item)
              break;

          // Check for errors
          if (index >= count) {
            console.warn("YIKES!! DynamicSplitView can't find ", item, "in it's container", contentChildren)
            index = -1
          }

          return index
        }

        function split(item, orientation)
        {
          // Do we only have 1 child?
          if (count === 1)
          {
            // Yes, switch our orientation to the one requested
            this.orientation = orientation
          }

          // Are we adding a child in our current orientation?
          if (orientation === this.orientation)
          {
            // Yes, Create and configure a new child
            var newChildBase = d.createItem()
            if (newChildBase)
            {
              // Add it to our splitter items
              addItem(newChildBase)
            }
          }

          // Otherwise, we're splitting a child with a different orientation
          else
          {
            // Find the item's index
            var index = __indexOf(item)
            if (index >= 0)
            {
              // Create a new SplitView
              var newViewBase = d.createSplitView(null)
              var newSplitter = newViewBase.children[0]

              // Replace the item with the new one
              item = takeItem(index)
              insertItem(index, newViewBase)

              // Add the item to this new SplitView
              newSplitter.addItem(item)

              // Split the new SplitView to finish
              newSplitter.split(null, orientation)
            }
          }
        }

        function unsplit(item)
        {
          // Find the item's index
          var index = __indexOf(item)
          if (index >= 0)
          {
            // Can we delete the item?
            if (count > 1 || mySplitView)
            {
              // Remove and destroy the item
              takeItem(index).destroy()

              // Clean degenerate trees
              d.topSplitView.__cleanDegenerateTree()
            }
            else
            {
              console.log("DynamicSplitView, can't delete last item in top-most SplitView")
            }
          }
        }

        function __cleanDegenerateTree(index)
        {
          // Traverse the tree depth-first
          for(var i = 0; i<count; ++i)
            if (itemAt(i).objectName.startsWith("viewBase"))
              itemAt(i).children[0].__cleanDegenerateTree(i)

          // Okay, working bottom up ... If I've only a single child item, replace myself in my parent with my child
          if (mySplitView && count === 1)
          {
            // Remove myself from my parent
            mySplitView.takeItem(index)

            // Move my child to my parent
            mySplitView.insertItem(index, takeItem(0))

            // destroy myself (safe because this is last call in a tail-recursion)
            mySplitBase.destroy()
          }
        }
      }
    }

    property Component undefinedItemDelegate: ItemDelegate {
      Text {
        anchors.centerIn: parent
        text: "You forgot to define the\nDynamicSplitView.itemDelegate\nproperty"
        horizontalAlignment: Text.AlignHCenter
        font.pointSize: 24
      }
    }

    property Component notDerivedItemDelegate: ItemDelegate {
      Text {
        anchors.centerIn: parent
        text: "Your itemDelegate must derive from\nDynamicSplitView.ItemDelegate"
        horizontalAlignment: Text.AlignHCenter
        font.pointSize: 24
      }
    }

    function createSplitView(parent)
    {
      var item = splitViewComponent.createObject(parent)
      item.myIID = splitViewCount++
      item.objectName = "viewBase " + item.myIID
      item.children[0].objectName = "splitView " + item.myIID
      console.log("constructed", item, item.children[0])

      return item;
    }

    function createItem()
    {
      if (!root.itemDelegate)
      {
        console.warn("YIKES! You forgot to define the itemDelegate property.");
        root.itemDelegate = undefinedItemDelegate
      }

      var item = root.itemDelegate.createObject(null)
      if (item.objectName !== "<constructing ItemDelegate>")
      {
        console.warn("YIKES! Your itemDelegate must derive from DynamicSplitView.ItemDelegate")
        item.destroy()
        item = notDerivedItemDelegate.createObject(null)
      }
      else
      {
        item.myIID = splitItemCount++
        item.objectName = "itemBase " + item.myIID
        console.log("constructed", item)
      }

      return item
    }

    Component.onCompleted: {
      // Create initial item
      topSplitView = createSplitView(root).children[0]
      topSplitView.addItem(createItem())
    }
  }
}