Pixel art projects draw at very different sizes, so the fixed 18 px icons of behaviors, containers and rigidbodies were too big in some projects and too small in others. The size now lives in the project settings and travels with the project. - New field Symbol scale in the project settings dialog, below Play starts. It takes 0.1 to 4 with two decimals and defaults to 1. - The value is stored as project.symbolScale. Older projects load with 1, and values out of range are clamped on load. - Every change is its own undo step through a project command. - The factor scales the icon size, the spacing of icons that share a spot, the label offset and the selection frame of icon-only symbols. - The footprints in bounds.ts that Fit uses stay as they were. The hit area follows the icon, so clicks match what is drawn. - uiHooks reports the icon size so e2e can measure it. The e2e sum in the README is 1375. That is 1374 plus one new check, and 1374 itself has not been confirmed by CI yet. Tests: - ./check.sh: 157 files, 2326 tests, CHECK EXIT 0 (before 2320). - New tests/core/symbol-scale.test.ts with 5 tests (default, save and load, clamping, undo, icon frame), one more in project-settings.test.ts. - e2e 46f: dialog opens with 1, 0.5 plus Apply gives a 9 px icon, undo gives 18 again. Module 46: ALL PASSED, 13 checks. - Counter checks: without loading the value the save and load test fails. With the icon ignoring the factor exactly 46f fails. Both originals restored per cmp. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
63 lines
2.8 KiB
TypeScript
63 lines
2.8 KiB
TypeScript
/**
|
||
* What "Apply" in the Project settings dialog (#183) actually carries out. The dialog itself is a
|
||
* widget and needs a canvas; the rule behind it is a pure function and is tested here.
|
||
*/
|
||
import { describe, expect, it } from 'vitest';
|
||
import { settingsChanges, type ProjectSettings } from '../../src/editor/ProjectSettingsDialog';
|
||
|
||
const before: ProjectSettings = {
|
||
name: 'Demo project',
|
||
playFrom: 'start',
|
||
collisionLayers: ['Default', 'Enemies'],
|
||
symbolScale: 1,
|
||
};
|
||
|
||
describe('project settings', () => {
|
||
it('reports nothing to do when nothing was touched', () => {
|
||
expect(settingsChanges(before, { ...before, collisionLayers: ['Default', 'Enemies'] })).toEqual({
|
||
playFrom: 'start',
|
||
});
|
||
});
|
||
|
||
it('renames only when the name really differs', () => {
|
||
expect(settingsChanges(before, { ...before, name: 'Tetris' }).name).toBe('Tetris');
|
||
expect(settingsChanges(before, { ...before, name: 'Demo project' }).name).toBeUndefined();
|
||
});
|
||
|
||
it('trims the name and keeps the old one when only blanks are left', () => {
|
||
expect(settingsChanges(before, { ...before, name: ' Tetris ' }).name).toBe('Tetris');
|
||
expect(settingsChanges(before, { ...before, name: ' ' }).name).toBeUndefined();
|
||
});
|
||
|
||
it('writes the layers when one was added, renamed or dropped', () => {
|
||
const changed = (layers: string[]) => settingsChanges(before, { ...before, collisionLayers: layers });
|
||
expect(changed(['Default', 'Enemies', 'Pickups']).collisionLayers).toEqual([
|
||
'Default',
|
||
'Enemies',
|
||
'Pickups',
|
||
]);
|
||
expect(changed(['Default', 'Foes']).collisionLayers).toEqual(['Default', 'Foes']);
|
||
expect(changed(['Default']).collisionLayers).toEqual(['Default']);
|
||
});
|
||
|
||
it('hands back a copy of the layers, not the array the dialog goes on editing', () => {
|
||
const edited = ['Default', 'Foes'];
|
||
const change = settingsChanges(before, { ...before, collisionLayers: edited });
|
||
edited.push('Later');
|
||
expect(change.collisionLayers).toEqual(['Default', 'Foes']);
|
||
});
|
||
|
||
it('writes the symbol scale only when it changed, kept inside 0.1 to 4', () => {
|
||
expect(settingsChanges(before, { ...before, symbolScale: 1 }).symbolScale).toBeUndefined();
|
||
expect(settingsChanges(before, { ...before, symbolScale: 0.5 }).symbolScale).toBe(0.5);
|
||
expect(settingsChanges(before, { ...before, symbolScale: 0.01 }).symbolScale).toBe(0.1);
|
||
expect(settingsChanges(before, { ...before, symbolScale: 9 }).symbolScale).toBe(4);
|
||
expect(settingsChanges(before, { ...before, symbolScale: Number.NaN }).symbolScale).toBeUndefined();
|
||
});
|
||
|
||
it('always reports the start-scene switch – it is a preference, not an undo step', () => {
|
||
expect(settingsChanges(before, { ...before, playFrom: 'active' }).playFrom).toBe('active');
|
||
expect(settingsChanges(before, { ...before, playFrom: 'start' }).playFrom).toBe('start');
|
||
});
|
||
});
|