Tab walks the edit-server and friend screens through their buttons

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
Federico TaglianiandClaude Sonnet 5.5 committed 2026-11-02 00:06:47 +01:00
1 parent f8bfa06b90
commit 1446ced385
3 files changed
+108 -11

No files matched your search

+40 -7
View File
@@ -1676,10 +1676,12 @@ impl Screen {
pub fn focused_box(&self, (w, _h): (f32, f32)) -> Option<[f32; 4]> {
let y = match self {
Self::Edit { focus: 0, .. } => 66.0,
Self::Edit { .. } => 106.0,
Self::Edit { focus: 1, .. } => 106.0,
Self::Edit { .. } => return None,
Self::Direct { .. } => 116.0,
Self::Friend { focus: 0, .. } => 64.0,
Self::Friend { .. } => 105.0,
Self::Friend { focus: 1, .. } => 105.0,
Self::Friend { .. } => return None,
_ => return None,
};
Some([(w / 2.0).floor() - 100.0, y, 200.0, 20.0])
@@ -1691,11 +1693,20 @@ impl Screen {
address,
focus,
..
} => Some(if *focus == 0 { name } else { address }),
} => match *focus {
0 => Some(name),
1 => Some(address),
// A button has the focus.
_ => None,
},
Self::Direct { address } => Some(address),
Self::Friend {
code, relay, focus, ..
} => Some(if *focus == 0 { code } else { relay }),
} => match *focus {
0 => Some(code),
1 => Some(relay),
_ => None,
},
_ => None,
}
}
@@ -1776,9 +1787,31 @@ impl Screen {
128
}
}
pub fn tab(&mut self) {
if let Self::Edit { focus, .. } | Self::Friend { focus, .. } = self {
*focus = (*focus + 1) % 2;
/// Tab (`reverse`: Shift+Tab) through the focus order of `ManageServerScreen`
/// and the friend screen: the text fields, then the enabled `buttons`, then
/// round to the first field. `button` is the focused button, if any; a field
/// has the focus (`focus` below 2) only while no button does.
pub fn tab_dir(&mut self, reverse: bool, buttons: &[u8], button: &mut Option<u8>) {
let (Self::Edit { focus, .. } | Self::Friend { focus, .. }) = self else {
return;
};
let stops = 2 + buttons.len();
let at = match *button {
Some(id) => buttons.iter().position(|&b| b == id).map(|i| 2 + i),
None => Some(usize::from(*focus).min(1)),
}
.unwrap_or(0);
let next = if reverse {
(at + stops - 1) % stops
} else {
(at + 1) % stops
};
if next < 2 {
*focus = next as u8;
*button = None;
} else {
*focus = 2;
*button = Some(buttons[next - 2]);
}
}
/// Escape: back to the list, or out of it (true).
+19 -2
View File
@@ -3168,6 +3168,14 @@ Would you like to enable the Narrator or visit the Accessibility Settings?",
.map(|b| b.id);
if hit.is_some() {
self.focused_button = hit;
} else if matches!(
self.mode,
Mode::Multiplayer(
crate::multiplayer::Screen::Edit { .. } | crate::multiplayer::Screen::Friend { .. }
)
) {
// A press on a text field takes the focus from the button.
self.focused_button = None;
}
if matches!(self.mode, Mode::CreateFlat { .. }) {
self.flat_click(x, y, (w, h), hit);
@@ -3756,8 +3764,17 @@ Would you like to enable the Narrator or visit the Accessibility Settings?",
if self.rules.get_mut().is_some() {
return;
}
if let Mode::Multiplayer(screen) = &mut self.mode {
screen.tab();
if matches!(self.mode, Mode::Multiplayer(_)) {
let (w, h) = size;
let enabled: Vec<u8> = self
.buttons(w, h)
.iter()
.filter(|b| b.enabled)
.map(|b| b.id)
.collect();
if let Mode::Multiplayer(screen) = &mut self.mode {
screen.tab_dir(reverse, &enabled, &mut self.focused_button);
}
return;
}
let (w, h) = size;
+49 -2
View File
@@ -1152,6 +1152,53 @@ fn world_fields_edit_at_their_cursor() {
assert_eq!(f.title.search, "world");
}
/// `ManageServerScreen`'s focus order: the name, the address, the Server
/// Resource Packs button, Done, Cancel, then the name again.
#[test]
fn tab_walks_the_edit_server_screen_through_its_buttons() {
use crate::multiplayer::Screen;
let size = (854.0, 480.0);
let mut f = Fixture::new();
f.title.mode = Mode::Multiplayer(Screen::Edit {
index: None,
name: "Minecraft Server".into(),
address: "localhost".into(),
focus: 0,
packs: None,
});
let focus = |f: &Fixture| match &f.title.mode {
Mode::Multiplayer(Screen::Edit { focus, .. }) => (*focus, f.title.focused_button),
_ => panic!("edit"),
};
let mut seen = Vec::new();
for _ in 0..5 {
f.title.tab_dir(false, size);
seen.push(focus(&f));
}
// Address, then packs (60), Done (50), Cancel (51), and round to the name.
assert_eq!(
seen,
[
(1, None),
(2, Some(60)),
(2, Some(50)),
(2, Some(51)),
(0, None)
]
);
// A button has the focus: typing goes nowhere.
f.title.tab_dir(true, size);
assert_eq!(focus(&f), (2, Some(51)));
f.title.type_text("x");
let Mode::Multiplayer(Screen::Edit { name, address, .. }) = &f.title.mode else {
panic!("edit");
};
assert_eq!(
(name.as_str(), address.as_str()),
("Minecraft Server", "localhost")
);
}
#[test]
fn server_fields_edit_at_their_cursor() {
use winit::keyboard::KeyCode;
@@ -1179,8 +1226,8 @@ fn server_fields_edit_at_their_cursor() {
panic!("add server");
};
assert_eq!(address, "Yhost");
// Tab moves to the name, which edits at its own cursor.
f.title.tab();
// Shift+Tab moves back to the name, which edits at its own cursor.
f.title.tab_dir(true, (854.0, 480.0));
f.title.field_key(KeyCode::ArrowLeft, false, false);
f.title.type_text("X");
let Mode::Multiplayer(crate::multiplayer::Screen::Edit { name, .. }) = &f.title.mode else {