feat(settings/user/color): implement basic color picker without animations

This commit is contained in:
2025-12-27 16:48:10 +01:00
parent 5a023749ad
commit 22c9fe2742
6 changed files with 126 additions and 0 deletions

View File

@@ -4,6 +4,8 @@ import OptionsStartUp from "./Options/StartUp.vue";
import OptionsLanguage from "./Options/Language.vue";
import OptionsGbaMode from "./Options/GbaMode.vue";
import UserColor from "./User/Color.vue";
import ClockMenu from "./Clock/Menu.vue";
import UserMenu from "./User/Menu.vue";
import TouchScreenMenu from "./TouchScreen/Menu.vue";
@@ -113,6 +115,7 @@ const { selectedButton: selected, selectorPosition } = useButtonNavigation({
left: "user",
},
},
disabled: computed(() => settingsStore.currentSubMenu !== null),
});
const isSubmenu = (buttonName: string) => {
@@ -170,6 +173,8 @@ const viewComponents: Record<string, Component> = {
optionsStartUp: OptionsStartUp,
optionsLanguage: OptionsLanguage,
optionsGbaMode: OptionsGbaMode,
userColor: UserColor,
};
</script>

View File

@@ -0,0 +1,100 @@
<script setup lang="ts">
const GRID_SIZE = 4;
const GRID_START_X = 32;
const GRID_START_Y = 40;
const CELL_SIZE = 16;
const SPACING = 16;
const ANIMATION_SPEED = 475;
const app = useAppStore();
const { assets } = useAssets();
let selectedCol = app.color.col;
let selectedRow = app.color.row;
let selectorX = GRID_START_X + selectedCol * (CELL_SIZE + SPACING) - 4;
let selectorY = GRID_START_Y + selectedRow * (CELL_SIZE + SPACING) - 4;
const select = (col: number, row: number) => {
selectedCol = col;
selectedRow = row;
app.setColor(col, row);
};
useKeyDown((key) => {
switch (key) {
case "NDS_UP":
if (selectedRow > 0) select(selectedCol, selectedRow - 1);
break;
case "NDS_RIGHT":
if (selectedCol < GRID_SIZE - 1) select(selectedCol + 1, selectedRow);
break;
case "NDS_DOWN":
if (selectedRow < GRID_SIZE - 1) select(selectedCol, selectedRow + 1);
break;
case "NDS_LEFT":
if (selectedCol > 0) select(selectedCol - 1, selectedRow);
break;
}
});
useScreenClick((x, y) => {
const relativeX = x - GRID_START_X;
const relativeY = y - GRID_START_Y;
const col = Math.floor(relativeX / (CELL_SIZE + SPACING));
const row = Math.floor(relativeY / (CELL_SIZE + SPACING));
const cellLocalX = relativeX % (CELL_SIZE + SPACING);
const cellLocalY = relativeY % (CELL_SIZE + SPACING);
if (
rectContains([0, 0, GRID_SIZE, GRID_SIZE], [col, row]) &&
rectContains([0, 0, CELL_SIZE + 1, CELL_SIZE + 1], [cellLocalX, cellLocalY])
) {
select(col, row);
}
});
useRender((ctx, deltaTime) => {
ctx.drawImage(assets.settings.bottomScreen.user.colorPalette, 16, 32);
// animate
const finalSelectorX = GRID_START_X + selectedCol * (CELL_SIZE + SPACING) - 4;
const finalSelectorY = GRID_START_Y + selectedRow * (CELL_SIZE + SPACING) - 4;
const dx = finalSelectorX - selectorX;
const dy = finalSelectorY - selectorY;
if (dx > 0) {
selectorX += ANIMATION_SPEED * (deltaTime / 1000);
if (selectorX > finalSelectorX) selectorX = finalSelectorX;
} else if (dx < 0) {
selectorX -= ANIMATION_SPEED * (deltaTime / 1000);
if (selectorX < finalSelectorX) selectorX = finalSelectorX;
} else if (dy > 0) {
selectorY += ANIMATION_SPEED * (deltaTime / 1000);
if (selectorY > finalSelectorY) selectorY = finalSelectorY;
} else if (dy < 0) {
selectorY -= ANIMATION_SPEED * (deltaTime / 1000);
if (selectorY < finalSelectorY) selectorY = finalSelectorY;
}
// selector
ctx.fillStyle = APP_COLORS[selectedRow]![selectedCol]!;
const offsets = [0, 3, 7, 11, 15, 19, 22];
for (const offset of offsets) {
ctx.fillRect(selectorX + offset, selectorY + 0, 2, 1);
ctx.fillRect(selectorX + offset, selectorY + 23, 2, 1);
ctx.fillRect(selectorX + 0, selectorY + offset, 1, 2);
ctx.fillRect(selectorX + 23, selectorY + offset, 1, 2);
}
// preview
ctx.fillRect(192, 96, 32, 32);
});
defineOptions({
render: () => null,
});
</script>

View File

@@ -1,5 +1,20 @@
export const useAppStore = defineStore("app", {
state: () => ({
booted: false,
_color: { col: 0, row: 0 },
}),
actions: {
setColor(col: number, row: number) {
this._color = { col, row };
},
},
getters: {
color: (state) => ({
col: state._color.col,
row: state._color.row,
hex: APP_COLORS[state._color.row]![state._color.col]!,
}),
},
});

6
app/utils/app.ts Normal file
View File

@@ -0,0 +1,6 @@
export const APP_COLORS = [
["#61829a", "#ba4900", "#fb0018", "#fb8afb"],
["#fb9200", "#f3e300", "#aafb00", "#00fb00"],
["#00a238", "#49db8a", "#30baf3", "#0059f3"],
["#000092", "#8a00d3", "#d300eb", "#fb0092"],
];

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 B