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 OptionsLanguage from "./Options/Language.vue";
|
||||||
import OptionsGbaMode from "./Options/GbaMode.vue";
|
import OptionsGbaMode from "./Options/GbaMode.vue";
|
||||||
|
|
||||||
|
import UserColor from "./User/Color.vue";
|
||||||
|
|
||||||
import ClockMenu from "./Clock/Menu.vue";
|
import ClockMenu from "./Clock/Menu.vue";
|
||||||
import UserMenu from "./User/Menu.vue";
|
import UserMenu from "./User/Menu.vue";
|
||||||
import TouchScreenMenu from "./TouchScreen/Menu.vue";
|
import TouchScreenMenu from "./TouchScreen/Menu.vue";
|
||||||
@@ -113,6 +115,7 @@ const { selectedButton: selected, selectorPosition } = useButtonNavigation({
|
|||||||
left: "user",
|
left: "user",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
disabled: computed(() => settingsStore.currentSubMenu !== null),
|
||||||
});
|
});
|
||||||
|
|
||||||
const isSubmenu = (buttonName: string) => {
|
const isSubmenu = (buttonName: string) => {
|
||||||
@@ -170,6 +173,8 @@ const viewComponents: Record<string, Component> = {
|
|||||||
optionsStartUp: OptionsStartUp,
|
optionsStartUp: OptionsStartUp,
|
||||||
optionsLanguage: OptionsLanguage,
|
optionsLanguage: OptionsLanguage,
|
||||||
optionsGbaMode: OptionsGbaMode,
|
optionsGbaMode: OptionsGbaMode,
|
||||||
|
|
||||||
|
userColor: UserColor,
|
||||||
};
|
};
|
||||||
</script>
|
</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", {
|
export const useAppStore = defineStore("app", {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
booted: false,
|
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"],
|
||||||
|
];
|
||||||
BIN
public/images/settings/bottom-screen/user/color-palette.webp
Normal file
BIN
public/images/settings/bottom-screen/user/color-palette.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 304 B |
BIN
public/images/settings/bottom-screen/user/color-selector.webp
Normal file
BIN
public/images/settings/bottom-screen/user/color-selector.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 B |
Reference in New Issue
Block a user