mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 17:21:49 -10:00
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:
1 parent
f8bfa06b90
commit
1446ced385
3 files changed
+108
-11
No files matched your search
@@ -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).
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in new issue
Block a user