gpui: Ensure tab index handles are properly reused across frames (#35235)

Finn Evers created

This fixes an issue where focus handles with a tab index would get lost
between rendered frames because the focus handles were not reused for
the following paint cycle.

Release Notes:

- N/A

Change summary

crates/gpui/Cargo.toml      | 4 ++++
crates/gpui/src/tab_stop.rs | 2 +-
crates/gpui/src/window.rs   | 8 ++++++++
3 files changed, 13 insertions(+), 1 deletion(-)

Detailed changes

crates/gpui/Cargo.toml 🔗

@@ -287,6 +287,10 @@ path = "examples/shadow.rs"
 name = "svg"
 path = "examples/svg/svg.rs"
 
+[[example]]
+name = "tab_stop"
+path = "examples/tab_stop.rs"
+
 [[example]]
 name = "text"
 path = "examples/text.rs"

crates/gpui/src/tab_stop.rs 🔗

@@ -5,7 +5,7 @@ use crate::{FocusHandle, FocusId};
 /// Used to manage the `Tab` event to switch between focus handles.
 #[derive(Default)]
 pub(crate) struct TabHandles {
-    handles: Vec<FocusHandle>,
+    pub(crate) handles: Vec<FocusHandle>,
 }
 
 impl TabHandles {

crates/gpui/src/window.rs 🔗

@@ -702,6 +702,7 @@ pub(crate) struct PaintIndex {
     input_handlers_index: usize,
     cursor_styles_index: usize,
     accessed_element_states_index: usize,
+    tab_handle_index: usize,
     line_layout_index: LineLayoutIndex,
 }
 
@@ -2208,6 +2209,7 @@ impl Window {
             input_handlers_index: self.next_frame.input_handlers.len(),
             cursor_styles_index: self.next_frame.cursor_styles.len(),
             accessed_element_states_index: self.next_frame.accessed_element_states.len(),
+            tab_handle_index: self.next_frame.tab_handles.handles.len(),
             line_layout_index: self.text_system.layout_index(),
         }
     }
@@ -2237,6 +2239,12 @@ impl Window {
                 .iter()
                 .map(|(id, type_id)| (GlobalElementId(id.0.clone()), *type_id)),
         );
+        self.next_frame.tab_handles.handles.extend(
+            self.rendered_frame.tab_handles.handles
+                [range.start.tab_handle_index..range.end.tab_handle_index]
+                .iter()
+                .cloned(),
+        );
 
         self.text_system
             .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);