From e4d51cd51dc69ccc5b9688c2b5a8b093b015ab61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thea=20Sch=C3=B6bl?= Date: Tue, 31 Oct 2023 22:09:33 +0100 Subject: [PATCH] visual layout adjustments --- src/lib/assets/layouts/cc1.yml | 55 +++---- src/lib/assets/layouts/lite.yml | 146 +++++++++--------- .../components/layout/GenericLayout.svelte | 135 ++-------------- src/lib/components/layout/KeyText.svelte | 63 ++++++++ src/lib/components/layout/KeyboardKey.svelte | 102 ++++++++++++ src/lib/components/layout/Layout.svelte | 10 +- src/lib/components/layout/get-actions.ts | 19 +++ src/lib/components/layout/visual-layout.ts | 9 ++ src/lib/serialization/visual-layout.ts | 84 +++++++--- src/routes/config/layout/+page.svelte | 16 +- 10 files changed, 390 insertions(+), 249 deletions(-) create mode 100644 src/lib/components/layout/KeyText.svelte create mode 100644 src/lib/components/layout/KeyboardKey.svelte create mode 100644 src/lib/components/layout/get-actions.ts create mode 100644 src/lib/components/layout/visual-layout.ts diff --git a/src/lib/assets/layouts/cc1.yml b/src/lib/assets/layouts/cc1.yml index 37a5a4b2..2e951f12 100644 --- a/src/lib/assets/layouts/cc1.yml +++ b/src/lib/assets/layouts/cc1.yml @@ -1,36 +1,25 @@ name: CC1 col: - - gap: 156 + - row: + - switch: { d: 30, e: 31, n: 32, w: 33, s: 34 } + - switch: { d: 25, e: 26, n: 27, w: 28, s: 29 } + - switch: { d: 40, e: 41, n: 42, w: 43, s: 44 } + - switch: { d: 20, e: 21, n: 22, w: 23, s: 24 } + - switch: { d: 35, e: 36, n: 37, w: 38, s: 39 } + - switch: { d: 15, e: 16, n: 17, w: 18, s: 19 } + - switch: { d: 60, w: 61, n: 62, e: 63, s: 64 } + - switch: { d: 65, w: 66, n: 67, e: 68, s: 69 } + - switch: { d: 80, w: 81, n: 82, e: 83, s: 84 } + - switch: { d: 70, w: 71, n: 72, e: 73, s: 74 } + - switch: { d: 85, w: 86, n: 87, e: 88, s: 89 } + - switch: { d: 75, w: 76, n: 77, e: 78, s: 79 } + - row: + - switch: { d: 10, e: 11, n: 12, w: 13, s: 14 } + - switch: { d: 55, w: 56, n: 57, e: 58, s: 59 } + - row: + - switch: { d: 5, e: 6, n: 7, w: 8, s: 9 } + - switch: { d: 50, w: 51, n: 52, e: 53, s: 54 } + - offset: [ 0, 0 ] row: - - row: - - {d: 30, e: 31, n: 32, w: 33, s: 34} - - col: - - {d: 25, e: 26, n: 27, w: 28, s: 29} - - {d: 40, e: 41, n: 42, w: 43, s: 44} - - col: - - {d: 20, e: 21, n: 22, w: 23, s: 24} - - {d: 35, e: 36, n: 37, w: 38, s: 39} - - {d: 15, e: 16, n: 17, w: 18, s: 19} - - row: - - {d: 60, w: 61, n: 62, e: 63, s: 64} - - col: - - {d: 65, w: 66, n: 67, e: 68, s: 69} - - {d: 80, w: 81, n: 82, e: 83, s: 84} - - col: - - {d: 70, w: 71, n: 72, e: 73, s: 74} - - {d: 85, w: 86, n: 87, e: 88, s: 89} - - {d: 75, w: 76, n: 77, e: 78, s: 79} - - gap: 48 - margin-top: -32 - row: - - {d: 10, e: 11, n: 12, w: 13, s: 14} - - {d: 55, w: 56, n: 57, e: 58, s: 59} - - gap: 160 - row: - - {d: 5, e: 6, n: 7, w: 8, s: 9} - - {d: 50, w: 51, n: 52, e: 53, s: 54} - - gap: 320 - margin-top: -12 - row: - - {d: 0, e: 1, n: 2, w: 3, s: 4} - - {d: 45, w: 46, n: 47, e: 48, s: 49} + - switch: { d: 0, e: 1, n: 2, w: 3, s: 4 } + - switch: { d: 45, w: 46, n: 47, e: 48, s: 49 } diff --git a/src/lib/assets/layouts/lite.yml b/src/lib/assets/layouts/lite.yml index f003090e..f3c33c24 100644 --- a/src/lib/assets/layouts/lite.yml +++ b/src/lib/assets/layouts/lite.yml @@ -1,87 +1,87 @@ name: Lite -row: - - col: - - id: 53 - - id: 54 - - id: 55 - - id: 56 - - id: 57 - - id: 58 - - id: 59 - - id: 60 - - id: 61 - - id: 62 - - id: 63 - - id: 64 - - id: 65 - - id: 66 +col: + - row: + - key: 53 + - key: 54 + - key: 55 + - key: 56 + - key: 57 + - key: 58 + - key: 59 + - key: 60 + - key: 61 + - key: 62 + - key: 63 + - key: 64 + - key: 65 + - key: 66 size: [ 2, 1 ] - - col: - - id: 39 + - row: + - key: 39 size: [ 1.5, 1 ] - - id: 40 - - id: 41 - - id: 42 - - id: 43 - - id: 44 - - id: 45 - - id: 46 - - id: 47 - - id: 48 - - id: 49 - - id: 50 - - id: 51 - - id: 52 + - key: 40 + - key: 41 + - key: 42 + - key: 43 + - key: 44 + - key: 45 + - key: 46 + - key: 47 + - key: 48 + - key: 49 + - key: 50 + - key: 51 + - key: 52 size: [ 1.5, 1 ] - - col: - - id: 26 + - row: + - key: 26 size: [ 1.75, 1 ] - - id: 27 - - id: 28 - - id: 29 - - id: 30 - - id: 31 - - id: 32 - - id: 33 - - id: 34 - - id: 35 - - id: 36 - - id: 37 - - id: 38 + - key: 27 + - key: 28 + - key: 29 + - key: 30 + - key: 31 + - key: 32 + - key: 33 + - key: 34 + - key: 35 + - key: 36 + - key: 37 + - key: 38 size: [ 2.25, 1 ] - - col: - - id: 12 + - row: + - key: 12 size: [ 2, 1 ] - - id: 13 - - id: 14 - - id: 15 - - id: 16 - - id: 17 - - id: 18 - - id: 19 - - id: 20 - - id: 21 - - id: 22 - - id: 23 - - id: 24 - - id: 25 - - col: - - id: 0 - - id: 1 + - key: 13 + - key: 14 + - key: 15 + - key: 16 + - key: 17 + - key: 18 + - key: 19 + - key: 20 + - key: 21 + - key: 22 + - key: 23 + - key: 24 + - key: 25 + - row: + - key: 0 + - key: 1 size: [ 1.25, 1 ] - - id: 2 + - key: 2 size: [ 1.25, 1 ] - - id: 3 + - key: 3 size: [ 2, 1 ] - - id: 4 - - id: 5 - - id: 6 + - key: 4 + - key: 5 + - key: 6 size: [ 2, 1 ] - - id: 7 + - key: 7 size: [ 1.25, 1 ] - - id: 8 + - key: 8 size: [ 1.25, 1 ] - - id: 9 - - id: 10 - - id: 11 + - key: 9 + - key: 10 + - key: 11 diff --git a/src/lib/components/layout/GenericLayout.svelte b/src/lib/components/layout/GenericLayout.svelte index 48198627..ff43dcb1 100644 --- a/src/lib/components/layout/GenericLayout.svelte +++ b/src/lib/components/layout/GenericLayout.svelte @@ -1,24 +1,19 @@ + +{#each positions as position, layer} + {@const [action, changed] = getActions(layer, key.id, $layout, $changes)} + {@const isActive = layer === $activeLayer} + {@const direction = [(middle[0] - margin * 3) / position[0], (middle[1] - margin * 3) / position[1]]} + + {#if action.code !== 0} + {action.icon || action.id || `0x${action.code?.toString(16)}`} + {/if} + {#if changed} + + {/if} + +{/each} + + diff --git a/src/lib/components/layout/KeyboardKey.svelte b/src/lib/components/layout/KeyboardKey.svelte new file mode 100644 index 00000000..6c7f6d20 --- /dev/null +++ b/src/lib/components/layout/KeyboardKey.svelte @@ -0,0 +1,102 @@ + + + + {#if key.shape === "square"} + + + {:else if key.shape === "quarter-circle"} + {@const innerMargin = margin / 2} + {@const r1 = sizeX / 2 - margin} + {@const p1 = r1 - innerMargin} + {@const r2 = r1 - sizeY + innerMargin * 2} + {@const p2 = r2 - innerMargin} + {@const multiplier = 1.4} + + + + + {/if} + + + diff --git a/src/lib/components/layout/Layout.svelte b/src/lib/components/layout/Layout.svelte index c96f3e9f..54d7895e 100644 --- a/src/lib/components/layout/Layout.svelte +++ b/src/lib/components/layout/Layout.svelte @@ -3,9 +3,11 @@ import LayoutCC1 from "$lib/components/layout/LayoutCC1.svelte" import {action} from "$lib/title" import GenericLayout from "$lib/components/layout/GenericLayout.svelte" + import {getContext} from "svelte" + import type {Writable} from "svelte/store" $: device = $serialPort?.device ?? "ONE" - let activeLayer = 0 + const activeLayer = getContext>("active-layer") const layers = [ ["Numeric Layer", "123", 1], @@ -20,8 +22,8 @@ @@ -29,7 +31,7 @@ {#if device === "ONE"} - + {:else}

Unsupported device ({$serialPort?.device})

diff --git a/src/lib/components/layout/get-actions.ts b/src/lib/components/layout/get-actions.ts new file mode 100644 index 00000000..97a95825 --- /dev/null +++ b/src/lib/components/layout/get-actions.ts @@ -0,0 +1,19 @@ +import type {CharaLayout} from "$lib/serialization/layout" +import type {Change} from "$lib/serial/connection" +import {KEYMAP_CODES} from "$lib/serial/keymap-codes" +import type {KeyInfo} from "$lib/serial/keymap-codes" + +export function getActions( + layer: number, + id: number, + layout: CharaLayout, + changes: Change[], +): [KeyInfo, boolean] { + const actionId = layout?.[layer][id] + const changedId = changes.findLast(it => it?.layout?.[layer]?.[id] !== undefined)?.layout?.[layer]?.[id] + if (changedId !== undefined) { + return [KEYMAP_CODES[changedId] ?? {code: changedId}, true] + } else { + return [KEYMAP_CODES[actionId] ?? {code: actionId}, false] + } +} diff --git a/src/lib/components/layout/visual-layout.ts b/src/lib/components/layout/visual-layout.ts new file mode 100644 index 00000000..1647c496 --- /dev/null +++ b/src/lib/components/layout/visual-layout.ts @@ -0,0 +1,9 @@ +export interface VisualLayoutConfig { + scale: number + inactiveScale: number + inactiveOpacity: number + strokeWidth: number + margin: number + fontSize: number + iconFontSize: number +} diff --git a/src/lib/serialization/visual-layout.ts b/src/lib/serialization/visual-layout.ts index 3d10b895..dc3999ea 100644 --- a/src/lib/serialization/visual-layout.ts +++ b/src/lib/serialization/visual-layout.ts @@ -1,17 +1,32 @@ export interface VisualLayout { name: string - row: VisualLayoutRow[] + col: VisualLayoutRow[] } -export interface VisualLayoutRow { - col: VisualLayoutKey[] +interface Positionable { + offset: [number, number] + rotate: number } -export interface VisualLayoutKey { - id: number +export interface VisualLayoutRow extends Positionable { + row: Array +} + +export interface VisualLayoutKey extends Positionable { + key: number size?: [number, number] } +export interface VisualLayoutSwitch extends Positionable { + switch: { + n: number + e: number + w: number + s: number + d: number + } +} + export interface CompiledLayout { name: string size: [number, number] @@ -20,9 +35,11 @@ export interface CompiledLayout { export interface CompiledLayoutKey { id: number - type: "key" | "dpad" + shape: "quarter-circle" | "square" + cornerRadius: number size: [number, number] pos: [number, number] + rotate: number } export function compileLayout(layout: VisualLayout): CompiledLayout { @@ -33,21 +50,52 @@ export function compileLayout(layout: VisualLayout): CompiledLayout { } let y = 0 - for (const {col} of layout.row) { - let x = 0 + for (const {row, offset} of layout.col) { + let x = offset?.[0] ?? 0 + y += offset?.[1] ?? 0 let maxHeight = 0 - for (const {id, size} of col) { - const [width, height] = size ?? [1, 1] + for (const info of row) { + const [ox, oy] = info.offset || [0, 0] + const rotate = info.rotate || 0 + if ("key" in info) { + const [width, height] = info.size ?? [1, 1] - compiled.keys.push({ - id, - type: "key", - size: [width, height], - pos: [x, y], - }) + compiled.keys.push({ + id: info.key, + shape: "square", + size: [width, height], + pos: [x + ox, y + oy], + cornerRadius: 0.1, + rotate, + }) - x += width - maxHeight = Math.max(maxHeight, height) + x += width + ox + maxHeight = Math.max(maxHeight, height + oy) + } else if ("switch" in info) { + const cx = x + ox + 1 + const cy = y + oy + 1 + for (const [id, i] of [info.switch.n, info.switch.e, info.switch.s, info.switch.w].entries()) { + compiled.keys.push({ + id, + shape: "quarter-circle", + cornerRadius: 0, + size: [2, 0.6], + pos: [cx, cy], + rotate: (Math.PI / 2) * i + Math.PI / 4, + }) + } + compiled.keys.push({ + id: info.switch.d, + shape: "square", + cornerRadius: 0.5, + size: [0.8, 0.8], + pos: [x + 0.6 + ox, y + 0.6 + oy], + rotate: 0, + }) + + x += 2 + ox + maxHeight = Math.max(maxHeight, 2 + oy) + } } y += maxHeight compiled.size[0] = Math.max(compiled.size[0], x) diff --git a/src/routes/config/layout/+page.svelte b/src/routes/config/layout/+page.svelte index a790f9a6..12e048e0 100644 --- a/src/routes/config/layout/+page.svelte +++ b/src/routes/config/layout/+page.svelte @@ -2,12 +2,14 @@ import {share} from "$lib/share" import {layout} from "$lib/serial/connection" import tippy from "tippy.js" - import {onMount} from "svelte" + import {onMount, setContext} from "svelte" import Layout from "$lib/components/layout/Layout.svelte" import {csvLayoutToJson, isCsvLayout} from "$lib/compat/legacy-layout" import {charaFileFromUriComponent, charaFileToUriComponent} from "$lib/share/share-url" import type {CharaLayoutFile} from "$lib/share/chara-file" import SharePopup from "../SharePopup.svelte" + import type {VisualLayoutConfig} from "$lib/components/layout/visual-layout" + import {writable} from "svelte/store" onMount(async () => { const url = new URL(window.location.href) @@ -53,6 +55,18 @@ if (importedLayout.type === "layout" && importedLayout.charaVersion === 1) $layout = importedLayout.layout } + setContext("visual-layout-config", { + scale: 50, + inactiveScale: 0.6, + inactiveOpacity: 0.4, + strokeWidth: 1, + margin: 5, + fontSize: 9, + iconFontSize: 14, + }) + + setContext("active-layer", writable(0)) + let fileInput: HTMLInputElement