feat(control): grid snap, NPC context actions, and overlay dim fix
Re-enable users-branch UI, snap session tokens to square/hex grid from the control preview, refine inactive/open-info NPC menus, block marker actions while an effect brush is active, and dim materials/NPC overlays only when they are open. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+29
-1
@@ -19,6 +19,7 @@ import {
|
||||
stripProjectZipExtension,
|
||||
} from '../shared/project/projectZipExtension';
|
||||
import type { Project } from '../shared/types';
|
||||
import { asNpcId } from '../shared/types/ids';
|
||||
|
||||
import { EffectsStore, effectsDefaultTool } from './effects/effectsStore';
|
||||
import { SceneDarknessStore } from './effects/sceneDarknessStore';
|
||||
@@ -34,6 +35,7 @@ import { PlayersStore } from './players/playersStore';
|
||||
import { SceneNpcTokensSessionStore } from './players/sceneNpcTokensSessionStore';
|
||||
import { ScenePlayerTokensSessionStore } from './players/scenePlayerTokensSessionStore';
|
||||
import { SceneTokensSessionStore } from './tokens/sceneTokensSessionStore';
|
||||
import { TokenGridSnapSessionStore } from './tokens/tokenGridSnapSessionStore';
|
||||
import { TokensStore } from './tokens/tokensStore';
|
||||
import { installAutoUpdater } from './update/installAutoUpdater';
|
||||
import { getAppSemanticVersion, getOptionalBuildNumber } from './versionInfo';
|
||||
@@ -156,6 +158,7 @@ const npcsOverlayStore = new NpcsOverlayStore();
|
||||
const sceneTokensSessionStore = new SceneTokensSessionStore();
|
||||
const sceneNpcTokensSessionStore = new SceneNpcTokensSessionStore();
|
||||
const scenePlayerTokensSessionStore = new ScenePlayerTokensSessionStore();
|
||||
const tokenGridSnapSessionStore = new TokenGridSnapSessionStore();
|
||||
let tokensStore: TokensStore | null = null;
|
||||
let playersStore: PlayersStore | null = null;
|
||||
|
||||
@@ -226,6 +229,13 @@ function emitSceneTokensSessionState(): void {
|
||||
}
|
||||
}
|
||||
|
||||
function emitTokenGridSnapState(): void {
|
||||
const { enabled } = tokenGridSnapSessionStore.getState();
|
||||
for (const win of BrowserWindow.getAllWindows()) {
|
||||
win.webContents.send(ipcChannels.tokenGridSnap.stateChanged, { enabled });
|
||||
}
|
||||
}
|
||||
|
||||
function emitPlayersState(): void {
|
||||
const players = playersStore?.listPlayers() ?? [];
|
||||
const teams = playersStore?.listTeams() ?? [];
|
||||
@@ -432,6 +442,7 @@ async function main() {
|
||||
sceneTokensSessionStore.reset();
|
||||
sceneNpcTokensSessionStore.reset();
|
||||
scenePlayerTokensSessionStore.reset();
|
||||
tokenGridSnapSessionStore.reset();
|
||||
if (USERS_BRANCH_FEATURES_ENABLED) {
|
||||
const playerIds = Array.isArray(req?.playerIds) ? req.playerIds.map(String).filter(Boolean) : [];
|
||||
if (playerIds.length > 0) {
|
||||
@@ -450,11 +461,14 @@ async function main() {
|
||||
emitSceneTokensSessionState();
|
||||
emitSceneNpcTokensSessionState();
|
||||
emitScenePlayerTokensSessionState();
|
||||
emitTokenGridSnapState();
|
||||
emitEffectsState();
|
||||
return { ok: true };
|
||||
});
|
||||
registerHandler(ipcChannels.windows.closeMultiWindow, () => {
|
||||
closeMultiWindow();
|
||||
tokenGridSnapSessionStore.reset();
|
||||
emitTokenGridSnapState();
|
||||
return { ok: true };
|
||||
});
|
||||
registerHandler(ipcChannels.windows.syncChromeTitles, ({ localeTag }) => {
|
||||
@@ -507,8 +521,13 @@ async function main() {
|
||||
closeSceneEditorWindow();
|
||||
return { ok: true };
|
||||
});
|
||||
registerHandler(ipcChannels.windows.openNpcs, () => {
|
||||
registerHandler(ipcChannels.windows.openNpcs, (req) => {
|
||||
openNpcsWindow();
|
||||
const npcId = req?.npcId ? asNpcId(String(req.npcId)) : null;
|
||||
if (npcId) {
|
||||
npcsOverlayStore.dispatch({ kind: 'show', npcId });
|
||||
emitNpcsOverlayState();
|
||||
}
|
||||
return { ok: true };
|
||||
});
|
||||
registerHandler(ipcChannels.windows.closeNpcs, () => {
|
||||
@@ -576,6 +595,7 @@ async function main() {
|
||||
sceneTokensSessionStore.reset();
|
||||
sceneNpcTokensSessionStore.reset();
|
||||
scenePlayerTokensSessionStore.reset();
|
||||
tokenGridSnapSessionStore.reset();
|
||||
emitEffectsState();
|
||||
emitMaterialsOverlayState();
|
||||
emitNpcsOverlayState();
|
||||
@@ -585,6 +605,7 @@ async function main() {
|
||||
emitSceneTokensSessionState();
|
||||
emitSceneNpcTokensSessionState();
|
||||
emitScenePlayerTokensSessionState();
|
||||
emitTokenGridSnapState();
|
||||
emitSessionState();
|
||||
return { ok: true };
|
||||
});
|
||||
@@ -1361,6 +1382,13 @@ async function main() {
|
||||
return { ok: true };
|
||||
});
|
||||
|
||||
registerHandler(ipcChannels.tokenGridSnap.getState, () => tokenGridSnapSessionStore.getState());
|
||||
registerHandler(ipcChannels.tokenGridSnap.setEnabled, ({ enabled }) => {
|
||||
const next = tokenGridSnapSessionStore.setEnabled(enabled);
|
||||
emitTokenGridSnapState();
|
||||
return next;
|
||||
});
|
||||
|
||||
registerHandler(ipcChannels.players.list, async () => {
|
||||
if (!USERS_BRANCH_FEATURES_ENABLED || !playersStore) {
|
||||
return { players: [], teams: [] };
|
||||
|
||||
Reference in New Issue
Block a user