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

orion-ecs / keen-eye / 20871273650

10 Jan 2026 02:23AM UTC coverage: 86.895% (-0.07%) from 86.962%
20871273650

push

github

tyevco
fix(ui): Fix UI widget tests for arrows, TabView visibility, and TextInput

- Use Unicode arrows (▼/▶) instead of ASCII (v/>) for accordion and tree view expand/collapse indicators
- Set visibility, UITabPanel, and UIHiddenTag on both scrollView and scrollContent in CreateTabView
- Fix UITextInput test assertions to expect ShowingPlaceholder=false when no placeholder text is provided

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

9264 of 12568 branches covered (73.71%)

Branch coverage included in aggregate %.

15 of 15 new or added lines in 6 files covered. (100.0%)

321 existing lines in 16 files now uncovered.

159741 of 181925 relevant lines covered (87.81%)

1.0 hits per line

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

98.75
/src/KeenEyes.UI/Systems/UITreeViewSystem.cs
1
using System.Numerics;
2
using KeenEyes.UI.Abstractions;
3

4
namespace KeenEyes.UI;
5

6
/// <summary>
7
/// System that handles tree view interactions: expansion and selection.
8
/// </summary>
9
/// <remarks>
10
/// <para>
11
/// This system processes interactions with tree view widgets including:
12
/// <list type="bullet">
13
/// <item>Expand/collapse nodes via arrow clicks</item>
14
/// <item>Selection via node content clicks</item>
15
/// <item>Double-click events for actions</item>
16
/// </list>
17
/// </para>
18
/// </remarks>
19
public sealed class UITreeViewSystem : SystemBase
20
{
21
    /// <inheritdoc/>
22
    public override void Update(float deltaTime)
23
    {
24
        // Handle expand arrow clicks
25
        ProcessExpandCollapseClicks();
1✔
26

27
        // Handle node selection clicks
28
        ProcessNodeSelectionClicks();
1✔
29
    }
1✔
30

31
    private void ProcessExpandCollapseClicks()
32
    {
33
        // Find expand arrows that were clicked
34
        foreach (var arrowEntity in World.Query<UITreeNodeExpandArrowTag, UIInteractable>())
1✔
35
        {
36
            ref readonly var interactable = ref World.Get<UIInteractable>(arrowEntity);
1✔
37

38
            if (!interactable.HasEvent(UIEventType.Click))
1✔
39
            {
40
                continue;
41
            }
42

43
            // Find the parent tree node
44
            var parent = World.GetParent(arrowEntity);
1✔
45
            while (parent.IsValid && !World.Has<UITreeNode>(parent))
1✔
46
            {
47
                parent = World.GetParent(parent);
1✔
48
            }
49

50
            if (!parent.IsValid || !World.Has<UITreeNode>(parent))
1✔
51
            {
52
                continue;
53
            }
54

55
            ref var node = ref World.Get<UITreeNode>(parent);
1✔
56
            if (!node.HasChildren)
1✔
57
            {
58
                continue;
59
            }
60

61
            // Toggle expansion
62
            node.IsExpanded = !node.IsExpanded;
1✔
63

64
            // Update visibility of child container
65
            if (node.ChildContainer.IsValid && World.Has<UIElement>(node.ChildContainer))
1✔
66
            {
67
                ref var childElement = ref World.Get<UIElement>(node.ChildContainer);
1✔
68
                childElement.Visible = node.IsExpanded;
1✔
69

70
                // Toggle UIHiddenTag so layout system properly reclaims space
71
                if (node.IsExpanded)
1✔
72
                {
73
                    if (World.Has<UIHiddenTag>(node.ChildContainer))
1✔
74
                    {
UNCOV
75
                        World.Remove<UIHiddenTag>(node.ChildContainer);
×
76
                    }
77
                }
78
                else
79
                {
80
                    if (!World.Has<UIHiddenTag>(node.ChildContainer))
1✔
81
                    {
82
                        World.Add(node.ChildContainer, new UIHiddenTag());
1✔
83
                    }
84
                }
85
            }
86

87
            // Mark tree view root dirty to force layout recalculation
88
            if (node.TreeView.IsValid && !World.Has<UILayoutDirtyTag>(node.TreeView))
1✔
89
            {
90
                World.Add(node.TreeView, new UILayoutDirtyTag());
1✔
91
            }
92

93
            // Update arrow rotation visual
94
            UpdateExpandArrowVisual(arrowEntity, node.IsExpanded);
1✔
95

96
            // Fire expand/collapse event
97
            if (node.TreeView.IsValid)
1✔
98
            {
99
                if (node.IsExpanded)
1✔
100
                {
101
                    World.Send(new UITreeNodeExpandedEvent(parent, node.TreeView));
1✔
102
                }
103
                else
104
                {
105
                    World.Send(new UITreeNodeCollapsedEvent(parent, node.TreeView));
1✔
106
                }
107
            }
108
        }
109
    }
1✔
110

111
    private void ProcessNodeSelectionClicks()
112
    {
113
        // Find tree nodes that were clicked (but not on expand arrow)
114
        foreach (var nodeEntity in World.Query<UITreeNode, UIInteractable>())
1✔
115
        {
116
            ref readonly var interactable = ref World.Get<UIInteractable>(nodeEntity);
1✔
117

118
            if (!interactable.HasEvent(UIEventType.Click))
1✔
119
            {
120
                continue;
121
            }
122

123
            ref var node = ref World.Get<UITreeNode>(nodeEntity);
1✔
124
            var treeView = node.TreeView;
1✔
125

126
            if (!treeView.IsValid || !World.Has<UITreeView>(treeView))
1✔
127
            {
128
                continue;
129
            }
130

131
            ref var treeViewData = ref World.Get<UITreeView>(treeView);
1✔
132

133
            // Deselect previous selection
134
            if (treeViewData.SelectedItem.IsValid &&
1✔
135
                treeViewData.SelectedItem != nodeEntity &&
1✔
136
                World.Has<UITreeNode>(treeViewData.SelectedItem))
1✔
137
            {
138
                ref var prevNode = ref World.Get<UITreeNode>(treeViewData.SelectedItem);
1✔
139
                prevNode.IsSelected = false;
1✔
140
                UpdateNodeSelectionVisual(treeViewData.SelectedItem, false);
1✔
141
            }
142

143
            // Select new node
144
            node.IsSelected = true;
1✔
145
            treeViewData.SelectedItem = nodeEntity;
1✔
146
            UpdateNodeSelectionVisual(nodeEntity, true);
1✔
147

148
            // Fire selection event
149
            World.Send(new UITreeNodeSelectedEvent(nodeEntity, treeView));
1✔
150

151
            // Check for double-click
152
            if (interactable.HasEvent(UIEventType.DoubleClick))
1✔
153
            {
154
                World.Send(new UITreeNodeDoubleClickedEvent(nodeEntity, treeView));
1✔
155
            }
156
        }
157
    }
1✔
158

159
    private void UpdateExpandArrowVisual(Entity arrowEntity, bool isExpanded)
160
    {
161
        // Update arrow text based on expansion state
162
        if (World.Has<UIText>(arrowEntity))
1✔
163
        {
164
            ref var text = ref World.Get<UIText>(arrowEntity);
1✔
165
            text.Content = isExpanded ? "▼" : "▶";
1✔
166
        }
167
    }
1✔
168

169
    private void UpdateNodeSelectionVisual(Entity nodeEntity, bool isSelected)
170
    {
171
        if (World.Has<UIStyle>(nodeEntity))
1✔
172
        {
173
            ref var style = ref World.Get<UIStyle>(nodeEntity);
1✔
174
            // Update background color based on selection state
175
            style.BackgroundColor = isSelected
1✔
176
                ? new Vector4(0.3f, 0.5f, 0.7f, 1f)
1✔
177
                : Vector4.Zero;
1✔
178
        }
179
    }
1✔
180
}
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