• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mobalazs / rotor-framework / 18919729013

29 Oct 2025 07:21PM UTC coverage: 85.379% (-0.1%) from 85.479%
18919729013

push

github

mobalazs
fix: update debug setting in bsconfig to enable debugging

1781 of 2086 relevant lines covered (85.38%)

1.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.08
/src/source/engine/builder/Tree.bs
1
import "TreeBase.bs"
2

3
namespace Rotor.ViewBuilder
4

5
    ' =====================================================================
6
    ' TreeRoot - Root node of the widget tree
7
    '
8
    ' Provides minimal API for rendering and erasing at the root level.
9
    ' =====================================================================
10
    class TreeRoot
11

12
        node as object
13

14
        children = {}
15

16
        viewModelState = {}
17

18
        id = ""
19
        HID = "0"
20
        vmHID = "0"
21
        parentHID = invalid
22
        isViewModel = true
23
        childrenHIDhash = {}
24

25
        function getFrameworkInstance() as object
26
            return GetGlobalAA().rotor_framework_helper.frameworkInstance
×
27
        end function
28

29
        sub render(payloads as dynamic, params = {} as object)
30
            for each payload in Rotor.Utils.ensureArray(payloads)
×
31
                if payload.DoesExist("id") = false and payload.DoesExist("HID") = false
×
32
                    payload.id = m.id
×
33
                    payload.HID = m.HID
×
34
                end if
35
            end for
36
            if Rotor.Utils.isValid(params.callback) then params.callbackScope = m
×
37
            m.getFrameworkInstance().builder.render(payloads, params)
×
38
        end sub
39

40
        sub erase(payloads as dynamic, shouldSkipNodePool)
41
            m.getFrameworkInstance().builder.erase(payloads, m.parentHID, shouldSkipNodePool)
×
42
        end sub
43

44
        sub destroy()
45
            m.node = invalid
1✔
46
        end sub
47

48
    end class
49

50
    ' =====================================================================
51
    ' WidgetTree - Main widget tree implementation extending WidgetTreeBase
52
    '
53
    ' Manages widget hierarchy, parent-child relationships,
54
    ' and ViewModel scope propagation through the tree.
55
    ' =====================================================================
56
    class WidgetTree extends Rotor.ViewBuilder.WidgetTreeBase
57

58
        ' sub new()
59
        ' end sub
60

61
        ' ---------------------------------------------------------------------
62
        ' init - Initializes the widget tree
63
        '
64
        sub init()
65
        end sub
66

67
        ' ---------------------------------------------------------------------
68
        ' destroy - Destroys the widget tree and cleans up resources
69
        '
70
        sub destroy()
71
            m.tree.destroy()
1✔
72
            m.tree_HIDHash.stack.Clear()
1✔
73
        end sub
74

75
        ' ---------------------------------------------------------------------
76
        ' add - Adds a widget to the tree and returns the widget instance
77
        '
78
        ' @param {object} config - Widget configuration with id and parentHID
79
        ' @param {object} ViewModelClass - Optional ViewModel class constructor (default: invalid)
80
        ' @returns {object} Created widget instance with generated HID
81
        '
82
        function add(config as object, ViewModelClass = invalid) as object
83

84
            if Rotor.Utils.isFunction(ViewModelClass as function) ' Custom View extends Widget
2✔
85
                ' bs:disable-next-line
86
                widget = new ViewModelClass()
1✔
87
            else
3✔
88
                widget = new Rotor.Widget() ' Standard Widget
1✔
89
            end if
90

91
            id = config.id
1✔
92

93
            ' Parse config properties
94
            widget.id = id
1✔
95
            widget.childrenHIDhash = {} ' prepare local HID cache
1✔
96
            widget.isRootChild = config.parentHID = "0" ' detect root
1✔
97
            widget.children = {} ' default
1✔
98

99
            ' Check if has parent widget
100
            if widget.isRootChild
2✔
101
                parent = m.tree
1✔
102
            else
3✔
103
                parent = m.get(config.parentHID)
1✔
104
            end if
105
            widget.parentHID = config.parentHID
1✔
106
            HID = m.generateHID(parent)
1✔
107

108
            ' register as child by readable id
109
            parent.children[LCase(id)] = widget
1✔
110

111
            ' register as child by readable HID (Hierarchical Identifier)
112
            parent.childrenHIDhash[HID] = true ' local cache for HID
1✔
113

114
            widget.HID = HID
1✔
115
            widget.parent = parent ' link parent widget
1✔
116

117
            if widget?.isViewModel = true
2✔
118
                widget.vmHID = widget.HID ' start new VM reference in hierarchy
1✔
119
            else
3✔
120
                widget.vmHID = parent.vmHID ' populate down the current VM reference in hierarchy
1✔
121
                VM = m.getByHID(parent.vmHID)
1✔
122
                widget.props = VM.props ' reference to ancestor's viewModel's props (sharing props across descendant widgets)
1✔
123
                widget.viewModelState = VM.viewModelState ' reference to ancestor ViewModel's viewModelState
1✔
124
            end if
125

126

127
            ' Build virtual widget tree
128
            m.tree_HIDHash.set(HID, widget)
1✔
129

130
            return widget
1✔
131
        end function
132

133
        ' ---------------------------------------------------------------------
134
        ' getChildrenWidgets - Gets child widgets of a parent in SceneGraph node order
135
        '
136
        ' @param {object} parentWidget - Parent widget to get children from
137
        ' @param {string} matchingPattern - Optional glob pattern to filter children (default: "")
138
        ' @returns {object} Array of child widgets in node order
139
        '
140
        function getChildrenWidgets(parentWidget as object, matchingPattern = "" as string) as object
141

142
            if parentWidget = invalid then return invalid
2✔
143

144
            ' Get all children in node order
145
            childrenWidgets = parentWidget.children.items()
1✔
146

147
            childrenWidgetsCount = childrenWidgets.Count()
1✔
148
            childrenNodes = parentWidget.node.getChildren(-1, 0)
1✔
149

150
            orderedWidgets = []
1✔
151
            for each node in childrenNodes
1✔
152
                isFound = false
1✔
153
                itemIndex = 0
1✔
154
                while isFound = false and itemIndex < childrenWidgetsCount
1✔
155
                    widget = childrenWidgets[itemIndex].value
1✔
156
                    if widget.node.isSameNode(node)
3✔
157
                        ' Apply ID filtering if pattern is provided
158
                        if matchingPattern = "" or m.matchesPattern(LCase(widget.id), LCase(matchingPattern))
2✔
159
                            orderedWidgets.push(widget)
1✔
160
                        end if
161
                        isFound = true
1✔
162
                    else
3✔
163
                        itemIndex++
1✔
164
                    end if
165
                end while
166
            end for
167

168
            return orderedWidgets
1✔
169
        end function
170

171
        ' ---------------------------------------------------------------------
172
        ' remove - Removes a widget from the tree by HID
173
        '
174
        ' @param {string} HID - Hierarchical ID of widget to remove
175
        '
176
        sub remove (HID as string)
177
            widget = m.getByHID(HID)
1✔
178
            ' if widget = invalid then return
179

180
            ' remove from parent
181
            parent = widget.parent
1✔
182
            parent.children.Delete(widget.id)
1✔
183

184
            parent.childrenHIDhash.Delete(widget.HID)
1✔
185

186
            m.tree_HIDHash.remove(HID)
1✔
187

188
            ' remove animators
189
            if widget.animators <> invalid and widget.animators.Count() > 0
2✔
190
                for each animatorId in widget.animators
×
191
                    widget.animator(animatorId).destroy()
×
192
                end for
193
            end if
194

195
            if widget.isViewModel = true
2✔
196
                widget.props.Clear()
1✔
197
                widget.viewModelState.Clear()
1✔
198
            end if
199

200
            widget.Clear()
1✔
201

202
        end sub
203

204
        ' ===== HELPER METHODS =====
205

206
        ' ---------------------------------------------------------------------
207
        ' isBranchOfRemove - Checks if widget is a top-level branch marked for removal
208
        '
209
        ' @param {object} widget - Widget to check
210
        ' @returns {boolean} True if widget is removal branch root
211
        '
212
        function isBranchOfRemove(widget as object) as boolean
213
            if false = widget.DoesExist("markedToRemove") then return false
2✔
214
            if widget.isRootChild = true
2✔
215
                return true
1✔
216
            end if
217

218
            return widget.parent.DoesExist("markedToRemove") ? false : true
1✔
219
        end function
220

221
        ' ---------------------------------------------------------------------
222
        ' isBranchOfAppend - Checks if widget is a top-level branch marked for append
223
        '
224
        ' @param {object} widget - Widget to check
225
        ' @returns {boolean} True if widget is append branch root
226
        '
227
        function isBranchOfAppend(widget as object) as boolean
228
            if false = widget.DoesExist("markedToAppend") then return false
1✔
229
            if widget.isRootChild = true
2✔
230
                return true
1✔
231
            end if
232
            return widget.parent.DoesExist("markedToAppend") ? false : true
1✔
233
        end function
234

235
        ' ---------------------------------------------------------------------
236
        ' getTreeItem - Gets tree item by HID or returns root if HID is empty
237
        '
238
        ' @param {string} HID - Hierarchical ID to lookup
239
        ' @returns {object} Widget at HID or tree root
240
        '
241
        function getTreeItem(HID)
242
            return HID = "" ? m.tree : m.getByHID(HID)
×
243
        end function
244

245
        ' Deprecated
246
        ' function checkRegexIncluded(part as string) as object
247
        '     if Left(part, 6) = "regex:"
248
        '         return {
249
        '             isRegex: true,
250
        '             regex: CreateObject("roRegex", Right(part, Len(part) - 6), "i")
251
        '         }
252
        '     else
253
        '         return {
254
        '             isRegex: false
255
        '         }
256
        '     end if
257
        ' end function
258

259
        ' ---------------------------------------------------------------------
260
        ' setRootNode - Sets the SceneGraph node for the tree root
261
        '
262
        ' @param {object} node - SceneGraph node to set as root
263
        '
264
        sub setRootNode (node as object)
265
            m.tree.node = node
1✔
266
        end sub
267

268
        ' ---------------------------------------------------------------------
269
        ' getRootNode - Gets the root SceneGraph node
270
        '
271
        ' @returns {object} Root SceneGraph node
272
        '
273
        function getRootNode() as object
274
            return m.tree.node
1✔
275
        end function
276
    end class
277

278
end namespace
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc