feat(settings/user/color): implement basic color picker without animations
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
100
app/components/Settings/BottomScreen/Menus/User/Color.vue
Normal file
100
app/components/Settings/BottomScreen/Menus/User/Color.vue
Normal 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>
|
||||
@@ -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
6
app/utils/app.ts
Normal 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"],
|
||||
];
|
||||
Reference in New Issue
Block a user