use super::{Cursor, KEYINPUT, TEXT_ENTRIES, UI_ENTRIES, wait_for_vblank};
use crate::{
mmio::KeyInput,
test::{ModuleFilter, TestOutcomes, TestOutcomesModules},
};
use core::fmt::Write;
fn adjust_index_for_new_parent(
offset_index: usize,
modules: TestOutcomesModules,
parent: &[&str],
) -> (usize, usize) {
let mut index = None;
for (module_index, module) in modules.enumerate() {
if module == parent {
index = Some(module_index);
break;
}
}
if let Some(index) = index {
if index.saturating_sub(offset_index) > 17 {
(index, index.saturating_sub(17))
} else if offset_index > index {
(index, index)
} else {
(index, offset_index)
}
} else {
(0, 0)
}
}
fn draw_modules(index: usize, offset_index: usize, modules: TestOutcomesModules) {
wait_for_vblank();
for y in 0..20 {
for x in 0..30 {
unsafe {
TEXT_ENTRIES.add(0x20 * y + x).write_volatile(0);
UI_ENTRIES.add(0x20 * y + x).write_volatile(0);
}
}
}
let mut cursor = unsafe { Cursor::new(TEXT_ENTRIES) };
for (row, module) in modules.skip(offset_index).take(18).enumerate() {
for _ in 0..(module.len() - 1) {
write!(cursor, " ").expect("couldn't write spaces");
}
writeln!(
cursor,
"{}",
module.last().expect("got an empty module list")
)
.expect("couldn't write");
let mut ui_cursor = unsafe { UI_ENTRIES.byte_add(0x40 * row) };
if index.saturating_sub(offset_index) == row {
for _ in 0..30 {
unsafe {
ui_cursor.write_volatile((4 << 12) | 1);
ui_cursor = ui_cursor.add(1);
}
}
} else {
for _ in 0..30 {
unsafe {
ui_cursor.write_volatile(0);
ui_cursor = ui_cursor.add(1);
}
}
}
}
}
fn find_parent_in_outcomes<'a>(
test_outcomes: &'a TestOutcomes,
parent: &[&str],
) -> Option<&'a [&'a str]> {
test_outcomes
.modules(parent)
.find(|&module| module == parent)
}
pub(super) fn show<'a, 'b>(
test_outcomes: &'a TestOutcomes,
parent: &'b [&'b str],
) -> Option<Option<ModuleFilter<'a>>>
where
'a: 'b,
{
let mut index = 0;
let mut offset_index = 0;
let mut old_keys = KeyInput::START;
let mut parent = find_parent_in_outcomes(test_outcomes, parent).unwrap_or(&[]);
loop {
draw_modules(index, offset_index, test_outcomes.modules(parent));
loop {
wait_for_vblank();
let keys = unsafe { KEYINPUT.read_volatile() };
if keys != old_keys {
if keys.contains(KeyInput::UP) {
index = index.saturating_sub(1);
old_keys = keys;
break;
}
if keys.contains(KeyInput::DOWN) {
index = index.saturating_add(1);
old_keys = keys;
break;
}
if keys.contains(KeyInput::LEFT) {
if let Some(current_module) = test_outcomes.modules(parent).nth(index)
&& parent.starts_with(current_module)
&& let Some((_, new_parent)) = current_module.split_last()
{
parent = new_parent;
old_keys = keys;
break;
}
}
if keys.contains(KeyInput::RIGHT) {
if let Some(current_module) = test_outcomes.modules(parent).nth(index) {
parent = current_module;
(index, offset_index) = adjust_index_for_new_parent(
offset_index,
test_outcomes.modules(parent),
parent,
);
old_keys = keys;
break;
}
}
if keys.contains(KeyInput::A) {
if index == 0 {
return Some(None);
} else {
return Some(
test_outcomes
.modules(parent)
.nth(index)
.map(ModuleFilter::new),
);
}
}
if keys.contains(KeyInput::B) || keys.contains(KeyInput::START) {
return None;
}
}
old_keys = keys;
}
}
}