diff --git a/app/components/Settings/BottomScreen/Menus/Menus.vue b/app/components/Settings/BottomScreen/Menus/Menus.vue index edc2c31..5df5a8e 100644 --- a/app/components/Settings/BottomScreen/Menus/Menus.vue +++ b/app/components/Settings/BottomScreen/Menus/Menus.vue @@ -69,12 +69,12 @@ const { selectedButton: selected, selectorPosition } = useButtonNavigation({ right: "optionsGbaMode", }, optionsGbaMode: { - down: "options", + down: ["options", false], left: "optionsLanguage", - up: "optionsStartUp", + up: ["optionsStartUp", false], }, optionsStartUp: { - right: "optionsGbaMode", + right: ["optionsGbaMode", false], down: "optionsLanguage", }, @@ -89,12 +89,12 @@ const { selectedButton: selected, selectorPosition } = useButtonNavigation({ right: "clockTime", }, clockTime: { - down: "clock", + down: ["clock", false], left: "clockAlarm", - up: "clockDate", + up: ["clockDate", false], }, clockDate: { - right: "clockTime", + right: ["clockTime", false], down: "clockAlarm", }, @@ -104,8 +104,8 @@ const { selectedButton: selected, selectorPosition } = useButtonNavigation({ up: "userName", }, userBirthday: { - down: "user", - up: "userColor", + down: ["user", false], + up: ["userColor", false], right: "userName", }, userName: { @@ -115,13 +115,13 @@ const { selectedButton: selected, selectorPosition } = useButtonNavigation({ up: "userColor", }, userMessage: { - down: "user", + down: ["user", false], left: "userName", - up: "userColor", + up: ["userColor", false], }, userColor: { - left: "userBirthday", - right: "userMessage", + left: ["userBirthday", false], + right: ["userMessage", false], down: "userName", }, diff --git a/app/composables/useButtonNavigation.ts b/app/composables/useButtonNavigation.ts index 1ff8350..0c77738 100644 --- a/app/composables/useButtonNavigation.ts +++ b/app/composables/useButtonNavigation.ts @@ -13,10 +13,10 @@ export const useButtonNavigation = >({ navigation: Record< keyof T, { - up?: keyof T | "last"; - down?: keyof T | "last"; - left?: keyof T; - right?: keyof T; + up?: keyof T | "last" | [buttonName: keyof T, blocked: boolean]; + down?: keyof T | "last" | [buttonName: keyof T, blocked: boolean]; + left?: keyof T | [buttonName: keyof T, blocked: boolean]; + right?: keyof T | [buttonName: keyof T, blocked: boolean]; horizontalMode?: "navigate" | "preview"; } >; @@ -30,6 +30,16 @@ export const useButtonNavigation = >({ const selectorPosition = ref(buttons[initialButton]!); const nextButton = ref(); + const getNavigationTarget = ( + value: Entry | [buttonName: Entry, blocked: boolean] | undefined, + ): { target: Entry | "last"; blocked: boolean } | null => { + if (!value) return null; + if (Array.isArray(value)) { + return { target: value[0]!, blocked: value[1] === false }; + } + return { target: value, blocked: false }; + }; + const buildNavigationGraph = ( nav: typeof navigation, ): Map> => { @@ -43,31 +53,42 @@ export const useButtonNavigation = >({ edges.set(button, new Set()); } - if (navConfig.up && navConfig.up !== "last") { - edges.get(button)!.add(navConfig.up); + const up = getNavigationTarget(navConfig.up); + const down = getNavigationTarget(navConfig.down); + const left = getNavigationTarget(navConfig.left); + const right = getNavigationTarget(navConfig.right); + + // handle blocked paths + if (up && up.target !== "last" && !up.blocked) { + edges.get(button)!.add(up.target); } - if (navConfig.down && navConfig.down !== "last") { - edges.get(button)!.add(navConfig.down); + if (down && down.target !== "last" && !down.blocked) { + edges.get(button)!.add(down.target); } - if (navConfig.left) { - edges.get(button)!.add(navConfig.left); + if (left && !left.blocked) { + edges.get(button)!.add(left.target); } - if (navConfig.right) { - edges.get(button)!.add(navConfig.right); + if (right && !right.blocked) { + edges.get(button)!.add(right.target); } - if (navConfig.up === "last" || navConfig.down === "last") { + if (up?.target === "last" || down?.target === "last") { for (const [otherButton, otherNav] of Object.entries(nav) as [ Entry, (typeof nav)[Entry], ][]) { if (otherButton === button) continue; + const otherUp = getNavigationTarget(otherNav.up); + const otherDown = getNavigationTarget(otherNav.down); + const otherLeft = getNavigationTarget(otherNav.left); + const otherRight = getNavigationTarget(otherNav.right); + if ( - otherNav.up === button || - otherNav.down === button || - otherNav.left === button || - otherNav.right === button + (otherUp?.target === button && !otherUp.blocked) || + (otherDown?.target === button && !otherDown.blocked) || + (otherLeft?.target === button && !otherLeft.blocked) || + (otherRight?.target === button && !otherRight.blocked) ) { edges.get(button)!.add(otherButton); } @@ -203,72 +224,90 @@ export const useButtonNavigation = >({ let targetButton: Entry | undefined; switch (key) { - case "NDS_UP": - if (!currentNav.up) return; + case "NDS_UP": { + const upConfig = getNavigationTarget(currentNav.up); + if (!upConfig) return; - if (currentNav.up === "last") { + if (upConfig.target === "last") { if (nextButton.value) { targetButton = nextButton.value; } else { - targetButton = currentNav.left ?? currentNav.right; + const leftConfig = getNavigationTarget(currentNav.left); + const rightConfig = getNavigationTarget(currentNav.right); + targetButton = leftConfig?.target ?? rightConfig?.target; } } else { - if (navigation[currentNav.up].down === "last") { + const targetNav = navigation[upConfig.target]; + const targetDownConfig = getNavigationTarget(targetNav?.down); + if (targetDownConfig?.target === "last") { nextButton.value = selectedButton.value as Entry; } - targetButton = currentNav.up; + targetButton = upConfig.target; } break; + } - case "NDS_DOWN": - if (!currentNav.down) return; + case "NDS_DOWN": { + const downConfig = getNavigationTarget(currentNav.down); + if (!downConfig) return; - if (currentNav.down === "last") { + if (downConfig.target === "last") { if (nextButton.value) { targetButton = nextButton.value; } else { - targetButton = currentNav.left ?? currentNav.right; + const leftConfig = getNavigationTarget(currentNav.left); + const rightConfig = getNavigationTarget(currentNav.right); + targetButton = leftConfig?.target ?? rightConfig?.target; } } else { - if (navigation[currentNav.down].up === "last") { + const targetNav = navigation[downConfig.target]; + const targetUpConfig = getNavigationTarget(targetNav?.up); + if (targetUpConfig?.target === "last") { nextButton.value = selectedButton.value as Entry; } - targetButton = currentNav.down; + targetButton = downConfig.target; } break; + } - case "NDS_LEFT": - if (!currentNav.left) return; + case "NDS_LEFT": { + const leftConfig = getNavigationTarget(currentNav.left); + if (!leftConfig) return; if (currentNav.horizontalMode === "preview") { - nextButton.value = currentNav.left; + nextButton.value = leftConfig.target; } else { - targetButton = currentNav.left; + targetButton = leftConfig.target; } break; + } - case "NDS_RIGHT": - if (!currentNav.right) return; + case "NDS_RIGHT": { + const rightConfig = getNavigationTarget(currentNav.right); + if (!rightConfig) return; if (currentNav.horizontalMode === "preview") { - nextButton.value = currentNav.right; + nextButton.value = rightConfig.target; } else { - targetButton = currentNav.right; + targetButton = rightConfig.target; } break; + } case "NDS_START": - case "NDS_A": + case "NDS_A": { onButtonClick?.(selectedButton.value); break; + } default: return; } if (targetButton) { - animateToButton(targetButton, null); + const path = findPath(graph, selectedButton.value, targetButton); + animateToButton(targetButton, path); } });