@@ -182,15 +182,21 @@ public void Tab_TraversesScrollablePanelChildren()
182182
183183 system . WindowStateService . AddWindow ( window ) ;
184184
185- // Act & Assert - Tab through panel children
186- system . FocusStateService . SetFocus ( window , button1 ) ;
187- Assert . True ( button1 . HasFocus ) ;
185+ // Panel is auto-focused by AddControl (first interactive control)
186+ // which delegates focus to its first child (button1)
187+ Assert . True ( panel . HasFocus , "Panel should be auto-focused after AddControl" ) ;
188+ Assert . True ( button1 . HasFocus , "First child should be focused via delegation" ) ;
188189
189- window . SwitchFocus ( backward : false ) ;
190- Assert . True ( button2 . HasFocus ) ;
190+ // Internal Tab within panel: button1 → button2 (panel handles this)
191+ var tabKey = new ConsoleKeyInfo ( '\t ' , ConsoleKey . Tab , false , false , false ) ;
192+ panel . ProcessKey ( tabKey ) ;
193+ Assert . True ( panel . HasFocus , "Panel should still have focus during internal Tab" ) ;
194+ Assert . True ( button2 . HasFocus , "Second child should be focused via internal Tab" ) ;
191195
196+ // SwitchFocus advances past panel → buttonAfter
192197 window . SwitchFocus ( backward : false ) ;
193- Assert . True ( buttonAfter . HasFocus ) ;
198+ Assert . True ( buttonAfter . HasFocus , "Control after panel should be focused" ) ;
199+ Assert . False ( panel . HasFocus , "Panel should have lost focus" ) ;
194200 }
195201
196202 [ Fact ]
@@ -378,15 +384,17 @@ public void Tab_AfterContainerBecomesHidden_SkipsItsChildren()
378384
379385 system . WindowStateService . AddWindow ( window ) ;
380386
381- // Initially, button2 is reachable
387+ // Initially, button2 is reachable through panel
382388 system . FocusStateService . SetFocus ( window , button1 ) ;
383389 window . SwitchFocus ( backward : false ) ;
384- Assert . True ( button2 . HasFocus ) ;
390+ // Panel is opaque: panel gets focus and delegates to button2
391+ Assert . True ( panel . HasFocus , "Panel should be focused" ) ;
392+ Assert . True ( button2 . HasFocus , "Button2 should be focused via panel delegation" ) ;
385393
386394 // Act - Hide panel
387395 panel . Visible = false ;
388396
389- // Assert - After hiding, button2 should not be reachable
397+ // Assert - After hiding, panel and its children should not be reachable
390398 system . FocusStateService . SetFocus ( window , button1 ) ;
391399 window . SwitchFocus ( backward : false ) ;
392400 Assert . False ( button2 . HasFocus ) ; // Skipped
@@ -398,7 +406,7 @@ public void Tab_AfterContainerBecomesHidden_SkipsItsChildren()
398406 #region ScrollablePanel Smart Focus Tests
399407
400408 [ Fact ]
401- public void ScrollablePanel_WithFocusableChildren_ChildrenGetFocus ( )
409+ public void ScrollablePanel_WithFocusableChildren_PanelAndChildGetFocus ( )
402410 {
403411 // Arrange
404412 var system = TestWindowSystemBuilder . CreateTestSystem ( ) ;
@@ -412,10 +420,10 @@ public void ScrollablePanel_WithFocusableChildren_ChildrenGetFocus()
412420
413421 system . WindowStateService . AddWindow ( window ) ;
414422
415- // Act & Assert - Child gets focus, not panel
423+ // Act & Assert - Panel is an opaque container: it gets focus AND delegates to child
416424 window . SwitchFocus ( backward : false ) ;
417- Assert . True ( button . HasFocus ) ;
418- Assert . False ( panel . HasFocus ) ; // Panel should not be focusable when has focusable children
425+ Assert . True ( panel . HasFocus , "Panel should be focused (opaque container)" ) ;
426+ Assert . True ( button . HasFocus , "Child should be focused via panel delegation" ) ;
419427 }
420428
421429 [ Fact ]
@@ -555,12 +563,14 @@ public void Tab_TraversesColumnWithScrollablePanel()
555563
556564 system . WindowStateService . AddWindow ( window ) ;
557565
558- // Act & Assert - Tab should traverse into panel, then to next column
559- system . FocusStateService . SetFocus ( window , button1 ) ;
560- Assert . True ( button1 . HasFocus ) ;
566+ // Grid auto-focuses → delegates to panel → delegates to button1
567+ Assert . True ( panel . HasFocus , "Panel should be auto-focused via grid delegation" ) ;
568+ Assert . True ( button1 . HasFocus , "Button1 should be focused via panel delegation" ) ;
561569
570+ // SwitchFocus advances past panel → button2
562571 window . SwitchFocus ( backward : false ) ;
563- Assert . True ( button2 . HasFocus ) ;
572+ Assert . True ( button2 . HasFocus , "Button in second column should be focused" ) ;
573+ Assert . False ( panel . HasFocus , "Panel should have lost focus" ) ;
564574 }
565575
566576 [ Fact ]
@@ -638,12 +648,15 @@ public void Tab_TraversesStickyTopControls()
638648
639649 system . WindowStateService . AddWindow ( window ) ;
640650
641- // Act & Assert - Tab should traverse sticky controls normally
642- system . FocusStateService . SetFocus ( window , stickyButton ) ;
643- Assert . True ( stickyButton . HasFocus ) ;
644-
651+ // Act & Assert - Tab reaches panel, which delegates to first child (stickyButton)
645652 window . SwitchFocus ( backward : false ) ;
646- Assert . True ( normalButton . HasFocus ) ;
653+ Assert . True ( panel . HasFocus , "Panel should be focused" ) ;
654+ Assert . True ( stickyButton . HasFocus , "Sticky button should be focused via delegation" ) ;
655+
656+ // Internal Tab within panel: stickyButton → normalButton
657+ var tabKey = new ConsoleKeyInfo ( '\t ' , ConsoleKey . Tab , false , false , false ) ;
658+ panel . ProcessKey ( tabKey ) ;
659+ Assert . True ( normalButton . HasFocus , "Normal button should be focused via internal Tab" ) ;
647660 }
648661
649662 [ Fact ]
@@ -665,10 +678,15 @@ public void Tab_TraversesStickyBottomControls()
665678
666679 system . WindowStateService . AddWindow ( window ) ;
667680
668- // Act & Assert - Tab should include sticky bottom controls
669- system . FocusStateService . SetFocus ( window , normalButton ) ;
681+ // Act & Assert - Tab reaches panel, delegates to first child (normalButton)
670682 window . SwitchFocus ( backward : false ) ;
671- Assert . True ( stickyButton . HasFocus ) ;
683+ Assert . True ( panel . HasFocus , "Panel should be focused" ) ;
684+ Assert . True ( normalButton . HasFocus , "Normal button should be focused via delegation" ) ;
685+
686+ // Internal Tab: normalButton → stickyButton
687+ var tabKey = new ConsoleKeyInfo ( '\t ' , ConsoleKey . Tab , false , false , false ) ;
688+ panel . ProcessKey ( tabKey ) ;
689+ Assert . True ( stickyButton . HasFocus , "Sticky bottom button should be focused via internal Tab" ) ;
672690 }
673691
674692 [ Fact ]
@@ -692,13 +710,19 @@ public void Tab_TraversesMixedStickyPositions()
692710
693711 system . WindowStateService . AddWindow ( window ) ;
694712
695- // Act & Assert - Tab should traverse all in order
696- system . FocusStateService . SetFocus ( window , stickyTop ) ;
713+ // Act & Assert - Tab reaches panel, delegates to first child (stickyTop)
697714 window . SwitchFocus ( backward : false ) ;
698- Assert . True ( normal . HasFocus ) ;
715+ Assert . True ( panel . HasFocus , "Panel should be focused" ) ;
716+ Assert . True ( stickyTop . HasFocus , "Sticky top should be focused via delegation" ) ;
699717
700- window . SwitchFocus ( backward : false ) ;
701- Assert . True ( stickyBottom . HasFocus ) ;
718+ // Internal Tab: stickyTop → normal
719+ var tabKey = new ConsoleKeyInfo ( '\t ' , ConsoleKey . Tab , false , false , false ) ;
720+ panel . ProcessKey ( tabKey ) ;
721+ Assert . True ( normal . HasFocus , "Normal button should be focused via internal Tab" ) ;
722+
723+ // Internal Tab: normal → stickyBottom
724+ panel . ProcessKey ( tabKey ) ;
725+ Assert . True ( stickyBottom . HasFocus , "Sticky bottom should be focused via internal Tab" ) ;
702726 }
703727
704728 #endregion
@@ -736,19 +760,22 @@ public void Tab_TraversesGridWithNestedPanelsAndSplitters()
736760
737761 system . WindowStateService . AddWindow ( window ) ;
738762
739- // Tab order: button1 (panel1) → button2 (panel1) → splitter → button3 (column2)
740- system . FocusStateService . SetFocus ( window , button1 ) ;
763+ // Grid auto-focuses → delegates to panel1 → delegates to button1
764+ Assert . True ( panel1 . HasFocus , "Panel should be auto-focused via grid delegation" ) ;
765+ Assert . True ( button1 . HasFocus , "First child should be focused via delegation" ) ;
741766
742- // Tab 1: button1 → button2
743- window . SwitchFocus ( backward : false ) ;
744- Assert . True ( button2 . HasFocus ) ;
767+ // Internal Tab: button1 → button2 (panel handles this)
768+ var tabKey = new ConsoleKeyInfo ( '\t ' , ConsoleKey . Tab , false , false , false ) ;
769+ panel1 . ProcessKey ( tabKey ) ;
770+ Assert . True ( panel1 . HasFocus , "Panel should still have focus during internal Tab" ) ;
771+ Assert . True ( button2 . HasFocus , "Second child should be focused via internal Tab" ) ;
745772
746- // Tab 2: button2 → splitter
773+ // SwitchFocus advances past panel → splitter
747774 window . SwitchFocus ( backward : false ) ;
748- Assert . False ( button2 . HasFocus ) ;
775+ Assert . False ( panel1 . HasFocus , "Panel should have lost focus" ) ;
749776 Assert . False ( button3 . HasFocus ) ; // Splitter should have focus
750777
751- // Tab 3 : splitter → button3
778+ // Tab: splitter → button3
752779 window . SwitchFocus ( backward : false ) ;
753780 Assert . True ( button3 . HasFocus ) ;
754781 }
@@ -777,10 +804,15 @@ public void Tab_TraversesGridWithStickyAndNormalControls()
777804
778805 system . WindowStateService . AddWindow ( window ) ;
779806
780- // Act & Assert
781- system . FocusStateService . SetFocus ( window , stickyTop ) ;
807+ // Act & Assert - Tab reaches panel, delegates to stickyTop
782808 window . SwitchFocus ( backward : false ) ;
783- Assert . True ( normal . HasFocus ) ;
809+ Assert . True ( panel . HasFocus , "Panel should be focused" ) ;
810+ Assert . True ( stickyTop . HasFocus , "Sticky top should be focused via delegation" ) ;
811+
812+ // Internal Tab: stickyTop → normal
813+ var tabKey = new ConsoleKeyInfo ( '\t ' , ConsoleKey . Tab , false , false , false ) ;
814+ panel . ProcessKey ( tabKey ) ;
815+ Assert . True ( normal . HasFocus , "Normal button should be focused via internal Tab" ) ;
784816 }
785817
786818 [ Fact ]
0 commit comments