Clean up UI a bit, need to fix transport again
This commit is contained in:
12
index.html
12
index.html
@ -109,7 +109,7 @@
|
||||
</a>
|
||||
<nav class="py-2 flex flex-wrap items-center text-base absolute right-0">
|
||||
<!-- Play Button -->
|
||||
<a title="Play button (Ctrl+P)" id="play-button-1" class="bar_button">
|
||||
<a title="Play button (Ctrl+P)" id="play-button" class="bar_button">
|
||||
<svg id="play-icon" class="w-7 h-7" fill="currentColor" viewBox="0 0 14 16">
|
||||
<path d="M0 .984v14.032a1 1 0 0 0 1.506.845l12.006-7.016a.974.974 0 0 0 0-1.69L1.506.139A1 1 0 0 0 0 .984Z"/>
|
||||
</svg>
|
||||
@ -120,7 +120,7 @@
|
||||
</a>
|
||||
|
||||
<!-- Stop button -->
|
||||
<a title="Stop button (Ctrl+R)" id="stop-button-1" class="bar_button">
|
||||
<a title="Stop button (Ctrl+R)" id="stop-button" class="bar_button">
|
||||
<svg class="w-7 h-7 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Z"/>
|
||||
<rect x="6.5" y="6.5" width="7" height="7" fill="selection_background" rx="1" ry="1"/>
|
||||
@ -136,13 +136,6 @@
|
||||
<p class="hidden lg:block text-xl pl-2 inline-block">Eval</p>
|
||||
</a>
|
||||
|
||||
<a title="Clear button" id="clear-button-1" class="bar_button">
|
||||
<svg class="w-7 h-7 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 18 20">
|
||||
<path d="M17 4h-4V2a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v2H1a1 1 0 0 0 0 2h1v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V6h1a1 1 0 1 0 0-2ZM7 2h4v2H7V2Zm1 14a1 1 0 1 1-2 0V8a1 1 0 0 1 2 0v8Zm4 0a1 1 0 0 1-2 0V8a1 1 0 0 1 2 0v8Z"/>
|
||||
</svg>
|
||||
<p class="hidden lg:block text-xl pl-2 inline-block">Clear</p>
|
||||
</a>
|
||||
|
||||
<a title="Share button" id="share-button" class="bar_button">
|
||||
<svg class="w-7 h-7 " aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 19 19">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.013 7.962a3.519 3.519 0 0 0-4.975 0l-3.554 3.554a3.518 3.518 0 0 0 4.975 4.975l.461-.46m-.461-4.515a3.518 3.518 0 0 0 4.975 0l3.553-3.554a3.518 3.518 0 0 0-4.974-4.975L10.3 3.7"/>
|
||||
@ -157,6 +150,7 @@
|
||||
<p class="hidden lg:block text-xl pl-2 inline-block">Docs</p>
|
||||
</a>
|
||||
|
||||
<div id="transport_viewer" class="pr-2 text-selection_background"></div>
|
||||
</nav>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@ -404,7 +404,7 @@ export const gif = (app: Editor) => (options: any): void => {
|
||||
duration = 10
|
||||
} = options;
|
||||
|
||||
let real_duration = duration * app.clock.pulse_duration * app.clock.ppqn;
|
||||
let real_duration = duration * app.clock.time_position.tick_duration * app.clock.ppqn;
|
||||
let fadeOutDuration = real_duration * 0.1;
|
||||
let visibilityDuration = real_duration - fadeOutDuration;
|
||||
const gifElement = document.createElement("img");
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { sendToServer, type OSCMessage } from "../../IO/OSC";
|
||||
import { oscMessages } from "../../IO/OSC";
|
||||
import { type Editor } from "../../main";
|
||||
|
||||
export const osc = () => (address: string, port: number, ...args: any[]): void => {
|
||||
export const osc = (app: Editor) => (address: string, port: number, ...args: any[]): void => {
|
||||
/**
|
||||
* Sends an OSC message to the server.
|
||||
*/
|
||||
@ -9,7 +10,7 @@ export const osc = () => (address: string, port: number, ...args: any[]): void =
|
||||
address: address,
|
||||
port: port,
|
||||
args: args,
|
||||
timetag: Math.round(Date.now()),
|
||||
timetag: Math.round(Date.now() - app.clock.getTimeDeviation()),
|
||||
} as OSCMessage);
|
||||
};
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@ export const singleElements = {
|
||||
line_numbers_checkbox: "show-line-numbers",
|
||||
time_position_checkbox: "show-time-position",
|
||||
tips_checkbox: "show-tips",
|
||||
transport_viewer: "transport_viewer",
|
||||
completion_checkbox: "show-completions",
|
||||
midi_clock_checkbox: "send-midi-clock",
|
||||
midi_channels_scripts: "midi-channels-scripts",
|
||||
@ -44,6 +45,11 @@ export const singleElements = {
|
||||
hydra_canvas: "hydra-bg",
|
||||
feedback: "feedback",
|
||||
scope: "scope",
|
||||
play_button: "play-button",
|
||||
play_label: "play-label",
|
||||
stop_button: "stop-button",
|
||||
play_icon: "play-icon",
|
||||
pause_icon: "pause-icon",
|
||||
} as const;
|
||||
|
||||
export type SingleElementsKeys = keyof typeof singleElements;
|
||||
@ -60,12 +66,6 @@ export type ElementMap = {
|
||||
| HTMLInputElement;
|
||||
};
|
||||
|
||||
export const buttonGroups = {
|
||||
play_buttons: ["play-button-1"],
|
||||
stop_buttons: ["stop-button-1"],
|
||||
clear_buttons: ["clear-button-1"],
|
||||
};
|
||||
|
||||
//@ts-ignore
|
||||
export const createDocumentationStyle = (app: Editor) => {
|
||||
/**
|
||||
|
||||
@ -3,6 +3,7 @@ import { vim } from "@replit/codemirror-vim";
|
||||
import { tryEvaluate } from "../Evaluator";
|
||||
import { hideDocumentation, showDocumentation } from "../Docs/Documentation";
|
||||
import { openSettingsModal, openUniverseModal } from "../Editor/FileManagement";
|
||||
import { resetTransportView, updatePlayButton } from "./UILogic";
|
||||
|
||||
export const registerFillKeys = (app: Editor) => {
|
||||
document.addEventListener("keydown", (event) => {
|
||||
@ -53,21 +54,21 @@ export const registerOnKeyDown = (app: Editor) => {
|
||||
|
||||
if (event.ctrlKey && event.key === "s") {
|
||||
event.preventDefault();
|
||||
app.setButtonHighlighting("stop", true);
|
||||
app.clock.stop();
|
||||
app.flashBackground("#404040", 200);
|
||||
requestAnimationFrame (() => {
|
||||
updatePlayButton(app);
|
||||
resetTransportView(app);
|
||||
});
|
||||
app.clock.stop()
|
||||
}
|
||||
|
||||
if (event.ctrlKey && event.key === "p") {
|
||||
event.preventDefault();
|
||||
if (app.isPlaying) {
|
||||
app.isPlaying = false;
|
||||
app.setButtonHighlighting("pause", true);
|
||||
app.clock.pause();
|
||||
} else {
|
||||
app.isPlaying = true;
|
||||
app.setButtonHighlighting("play", true);
|
||||
app.clock.start();
|
||||
}
|
||||
app.flashBackground("#404040", 200);
|
||||
requestAnimationFrame(() => {
|
||||
updatePlayButton(app);
|
||||
});
|
||||
app.clock.resume()
|
||||
}
|
||||
|
||||
// Ctrl + Shift + V: Vim Mode
|
||||
|
||||
@ -73,33 +73,22 @@ export const installInterfaceLogic = (app: Editor) => {
|
||||
openUniverseModal();
|
||||
});
|
||||
|
||||
app.buttonElements['play_buttons']!.forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
app.interface['play_button'].addEventListener("click", () => {
|
||||
if (app.isPlaying) {
|
||||
app.setButtonHighlighting("pause", true);
|
||||
app.isPlaying = !app.isPlaying;
|
||||
app.clock.pause();
|
||||
app.api.MidiConnection.sendStopMessage();
|
||||
} else {
|
||||
app.setButtonHighlighting("play", true);
|
||||
app.isPlaying = !app.isPlaying;
|
||||
app.clock.start();
|
||||
app.api.MidiConnection.sendStartMessage();
|
||||
app.clock.resume()
|
||||
}
|
||||
});
|
||||
updatePlayButton(app);
|
||||
});
|
||||
|
||||
app.buttonElements['clear_buttons']!.forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
app.setButtonHighlighting("clear", true);
|
||||
if (confirm("Do you want to reset the current universe?")) {
|
||||
app.universes[app.selected_universe] =
|
||||
structuredClone(template_universe);
|
||||
app.updateEditorView();
|
||||
}
|
||||
});
|
||||
app.interface['stop_button'].addEventListener("click", () => {
|
||||
app.isPlaying = false;
|
||||
app.clock.stop();
|
||||
updatePlayButton(app);
|
||||
});
|
||||
|
||||
|
||||
app.interface.documentation_button.addEventListener("click", () => {
|
||||
showDocumentation(app);
|
||||
});
|
||||
@ -140,13 +129,6 @@ export const installInterfaceLogic = (app: Editor) => {
|
||||
}
|
||||
});
|
||||
|
||||
app.interface.audio_nudge_range.addEventListener("input", () => {
|
||||
// TODO: rebuild this
|
||||
// app.clock.nudge = parseInt(
|
||||
// (app.interface.audio_nudge_range as HTMLInputElement).value,
|
||||
// );
|
||||
});
|
||||
|
||||
app.interface.dough_nudge_range.addEventListener("input", () => {
|
||||
app.dough_nudge = parseInt(
|
||||
(app.interface.dough_nudge_range as HTMLInputElement).value,
|
||||
@ -239,14 +221,6 @@ export const installInterfaceLogic = (app: Editor) => {
|
||||
app.flashBackground("#404040", 200);
|
||||
});
|
||||
|
||||
app.buttonElements['stop_buttons']!.forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
app.setButtonHighlighting("stop", true);
|
||||
app.isPlaying = false;
|
||||
app.clock.stop();
|
||||
});
|
||||
});
|
||||
|
||||
app.interface.local_button.addEventListener("click", () =>
|
||||
app.changeModeFromInterface("local"),
|
||||
);
|
||||
@ -537,3 +511,43 @@ export const installInterfaceLogic = (app: Editor) => {
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const updatePlayButton = (app: Editor) => {
|
||||
switch (app.clock.state) {
|
||||
case 'stopped':
|
||||
app.interface.play_label.innerText = "Play";
|
||||
updatePlayPauseIcon(app, "play");
|
||||
break;
|
||||
case 'paused':
|
||||
app.interface.play_label.innerText = "Resume";
|
||||
updatePlayPauseIcon(app, "play");
|
||||
break;
|
||||
case 'running':
|
||||
app.interface.play_label.innerText = "Pause";
|
||||
updatePlayPauseIcon(app, "pause");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export const updatePlayPauseIcon = (app: Editor, state: "play" | "pause"): void => {
|
||||
const { play_icon, pause_icon } = app.interface;
|
||||
|
||||
const isPlayIconHidden = play_icon.classList.contains("hidden");
|
||||
const isPauseIconHidden = pause_icon.classList.contains("hidden");
|
||||
|
||||
if (state === "play" && isPlayIconHidden) {
|
||||
play_icon.classList.remove("hidden");
|
||||
pause_icon.classList.add("hidden");
|
||||
} else if (state === "pause" && isPauseIconHidden) {
|
||||
play_icon.classList.add("hidden");
|
||||
pause_icon.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
export const resetTransportView = (app: Editor) => {
|
||||
requestAnimationFrame(() => {
|
||||
app.interface.transport_viewer.innerHTML = `<span class="text-xl text-neutral">00:00:00</span>`;
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
@ -122,8 +122,8 @@ export class MidiEvent extends AudibleEvent {
|
||||
const note = params.note ? params.note : 60;
|
||||
|
||||
const sustain = params.sustain
|
||||
? params.sustain * event.app.clock.pulse_duration * event.app.api.ppqn()
|
||||
: event.app.clock.pulse_duration * event.app.api.ppqn();
|
||||
? params.sustain * event.app.clock.time_position.tick_duration * event.app.api.ppqn()
|
||||
: event.app.clock.time_position.tick_duration * event.app.api.ppqn();
|
||||
|
||||
const bend = params.bend ? params.bend : undefined;
|
||||
|
||||
|
||||
@ -7,12 +7,16 @@ export interface TimePosition {
|
||||
bpm: number; ppqn: number; time: number;
|
||||
tick: number; beat: number; bar: number;
|
||||
num: number; den: number; grain: number;
|
||||
tick_duration: number;
|
||||
}
|
||||
|
||||
export class Clock {
|
||||
ctx: AudioContext;
|
||||
transportNode: ClockNode | null;
|
||||
time_position: TimePosition;
|
||||
startTime: number | null = null;
|
||||
elapsedTime: number = 0;
|
||||
state: 'running' | 'paused' | 'stopped' = 'stopped';
|
||||
|
||||
constructor(
|
||||
public app: Editor,
|
||||
@ -28,6 +32,7 @@ export class Clock {
|
||||
num: 0,
|
||||
den: 0,
|
||||
grain: 0,
|
||||
tick_duration: 0,
|
||||
};
|
||||
this.transportNode = null;
|
||||
this.ctx = ctx;
|
||||
@ -43,6 +48,53 @@ export class Clock {
|
||||
});
|
||||
}
|
||||
|
||||
public play(): void {
|
||||
if (this.state !== 'running') {
|
||||
this.elapsedTime = 0;
|
||||
this.state = 'running';
|
||||
}
|
||||
this.startTime = performance.now();
|
||||
this.app.api.MidiConnection.sendStartMessage();
|
||||
this.transportNode?.start();
|
||||
}
|
||||
|
||||
public pause(): void {
|
||||
this.state = 'paused';
|
||||
if (this.startTime !== null) {
|
||||
this.elapsedTime += performance.now() - this.startTime;
|
||||
this.startTime = null;
|
||||
}
|
||||
this.app.api.MidiConnection.sendStopMessage();
|
||||
this.transportNode?.pause();
|
||||
}
|
||||
|
||||
public resume(): void {
|
||||
if (this.state === 'stopped' || this.state === 'paused') {
|
||||
this.startTime = performance.now();
|
||||
this.state = 'running';
|
||||
this.app.api.MidiConnection.sendStartMessage();
|
||||
this.transportNode?.start();
|
||||
} else if (this.state === 'running') {
|
||||
this.state = 'paused';
|
||||
if (this.startTime !== null) {
|
||||
this.elapsedTime += performance.now() - this.startTime;
|
||||
this.startTime = null;
|
||||
}
|
||||
this.app.api.MidiConnection.sendStopMessage();
|
||||
this.transportNode?.pause();
|
||||
}
|
||||
}
|
||||
|
||||
public stop(): void {
|
||||
if (this.startTime !== null) {
|
||||
this.elapsedTime += performance.now() - this.startTime;
|
||||
this.startTime = null;
|
||||
}
|
||||
this.state = 'stopped';
|
||||
this.app.api.MidiConnection.sendStopMessage();
|
||||
this.transportNode?.stop();
|
||||
}
|
||||
|
||||
get grain(): number {
|
||||
return this.time_position.grain;
|
||||
}
|
||||
@ -85,20 +137,6 @@ export class Clock {
|
||||
return Math.floor(this.time_position.tick / this.ppqn)
|
||||
}
|
||||
|
||||
get pulse_duration(): number {
|
||||
/**
|
||||
* Returns the duration of a pulse in seconds.
|
||||
*/
|
||||
return 60 / this.time_position.bpm / this.time_position.ppqn;
|
||||
}
|
||||
|
||||
public pulse_duration_at_bpm(bpm: number = this.bpm): number {
|
||||
/**
|
||||
* Returns the duration of a pulse in seconds at a specific bpm.
|
||||
*/
|
||||
return 60 / bpm / this.time_position.ppqn;
|
||||
}
|
||||
|
||||
get bpm(): number {
|
||||
return this.time_position.bpm;
|
||||
}
|
||||
@ -126,7 +164,7 @@ export class Clock {
|
||||
* @param nudge - nudge in the future (in seconds)
|
||||
* @returns remainingTime
|
||||
*/
|
||||
const pulseDuration = this.pulse_duration;
|
||||
const pulseDuration = this.time_position.tick_duration;
|
||||
const nudgedTime = time + nudge;
|
||||
const nextTickTime = Math.ceil(nudgedTime / pulseDuration) * pulseDuration;
|
||||
const remainingTime = nextTickTime - nudgedTime;
|
||||
@ -146,39 +184,35 @@ export class Clock {
|
||||
const grain = n;
|
||||
const beat = Math.floor(n / ppqn) % num;
|
||||
const bar = Math.floor(n / ppqn / num);
|
||||
const time = n * this.pulse_duration;
|
||||
return { bpm, ppqn, time, tick, beat, bar, num, den, grain };
|
||||
const time = n * this.time_position.tick_duration;
|
||||
const tick_duration = this.time_position.tick_duration;
|
||||
return { bpm, ppqn, time, tick, beat, bar, num, den, grain, tick_duration };
|
||||
}
|
||||
|
||||
public convertPulseToSecond(n: number): number {
|
||||
/**
|
||||
* Converts a pulse to a second.
|
||||
*/
|
||||
return n * this.pulse_duration;
|
||||
return n * this.time_position.tick_duration;
|
||||
}
|
||||
|
||||
public start(): void {
|
||||
/**
|
||||
* Starts the TransportNode (starts the clock).
|
||||
*
|
||||
* @remark also sends a MIDI message if a port is declared
|
||||
*/
|
||||
this.app.api.MidiConnection.sendStartMessage();
|
||||
this.transportNode?.start();
|
||||
}
|
||||
|
||||
public pause(): void {
|
||||
this.app.api.MidiConnection.sendStopMessage();
|
||||
this.transportNode?.pause()
|
||||
}
|
||||
|
||||
public setSignature(num: number, den: number): void {
|
||||
this.transportNode?.setSignature(num, den);
|
||||
}
|
||||
|
||||
public stop(): void {
|
||||
this.app.api.MidiConnection.sendStopMessage();
|
||||
this.transportNode?.stop()
|
||||
public getElapsed(): number {
|
||||
if (this.startTime === null) {
|
||||
return this.elapsedTime;
|
||||
} else {
|
||||
return this.elapsedTime + (performance.now() - this.startTime);
|
||||
}
|
||||
}
|
||||
|
||||
public getTimeDeviation(grain: number, tick_duration: number): number {
|
||||
const idealTime = grain * tick_duration;
|
||||
const elapsedTime = this.getElapsed();
|
||||
const timeDeviation = elapsedTime - idealTime;
|
||||
return timeDeviation;
|
||||
}
|
||||
}
|
||||
@ -24,8 +24,10 @@ export class ClockNode extends AudioWorkletNode {
|
||||
num: message.data.num,
|
||||
den: message.data.den,
|
||||
grain: message.data.grain,
|
||||
tick_duration: message.data.tick_duration,
|
||||
}
|
||||
this.app.settings.send_clock ?? this.app.api.MidiConnection.sendMidiClock();
|
||||
this.updateTransportViewer();
|
||||
tryEvaluate(
|
||||
this.app,
|
||||
this.app.exampleIsPlaying
|
||||
@ -34,6 +36,15 @@ export class ClockNode extends AudioWorkletNode {
|
||||
);
|
||||
}
|
||||
};
|
||||
updateTransportViewer() {
|
||||
const { bar, beat, tick } = this.app.clock.time_position;
|
||||
const paddedBar = String(bar).padStart(2, '0');
|
||||
const paddedBeat = String(beat).padStart(2, '0');
|
||||
const paddedTick = String(tick).padStart(2, '0');
|
||||
requestAnimationFrame(() => {
|
||||
this.app.interface.transport_viewer.innerHTML = `<span class="text-xl text-neutral">${paddedBar}:${paddedBeat}:${paddedTick}</span>`;
|
||||
});
|
||||
}
|
||||
|
||||
start() {
|
||||
this.port.postMessage({ type: "start" });
|
||||
|
||||
@ -35,6 +35,7 @@ class TransportProcessor extends AudioWorkletProcessor {
|
||||
this.pauseTime = 0;
|
||||
this.totalPauseTime = 0;
|
||||
this.currentPulsePosition = 0;
|
||||
this.grain = 0;
|
||||
} else if (message.data.type === "bpm") {
|
||||
this.bpm = message.data.value;
|
||||
this.startTime = currentTime;
|
||||
@ -78,7 +79,8 @@ class TransportProcessor extends AudioWorkletProcessor {
|
||||
bpm: this.bpm,
|
||||
ppqn: this.ppqn,
|
||||
type: 'time',
|
||||
time: currentTime,
|
||||
//time: currentTime,
|
||||
time: adjustedCurrentTime,
|
||||
tick: currentTick,
|
||||
beat: currentBeat,
|
||||
bar: currentBar,
|
||||
@ -86,6 +88,7 @@ class TransportProcessor extends AudioWorkletProcessor {
|
||||
num: this.timeSignature[0],
|
||||
den: this.timeSignature[1],
|
||||
grain: this.grain,
|
||||
tick_duration: 60 / this.bpm / this.ppqn,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
91
src/main.ts
91
src/main.ts
@ -12,7 +12,7 @@ import {
|
||||
Universe,
|
||||
loadUniverserFromUrl,
|
||||
} from "./Editor/FileManagement";
|
||||
import { singleElements, buttonGroups, ElementMap, createDocumentationStyle } from "./DOM/DomElements";
|
||||
import { singleElements, ElementMap, createDocumentationStyle } from "./DOM/DomElements";
|
||||
import { registerFillKeys, registerOnKeyDown } from "./DOM/Keyboard";
|
||||
import { installEditor } from "./Editor/EditorSetup";
|
||||
import { documentation_factory, documentation_pages, showDocumentation, updateDocumentationContent } from "./Docs/Documentation";
|
||||
@ -125,7 +125,6 @@ export class Editor {
|
||||
// ================================================================================
|
||||
|
||||
this.initializeElements();
|
||||
this.initializeButtonGroups();
|
||||
this.setCanvas(this.interface["feedback"] as HTMLCanvasElement);
|
||||
|
||||
// ================================================================================
|
||||
@ -393,86 +392,6 @@ export class Editor {
|
||||
this.updateEditorView();
|
||||
}
|
||||
|
||||
setButtonHighlighting(
|
||||
button: "play" | "pause" | "stop" | "clear",
|
||||
highlight: boolean,
|
||||
) {
|
||||
/**
|
||||
* Sets the highlighting for a specific button.
|
||||
*
|
||||
* @param button - The button to highlight ("play", "pause", "stop", or "clear").
|
||||
* @param highlight - A boolean indicating whether to highlight the button or not.
|
||||
*/
|
||||
document.getElementById("play-label")!.textContent =
|
||||
button !== "pause" ? "Pause" : "Play";
|
||||
if (button !== "pause") {
|
||||
document.getElementById("pause-icon")!.classList.remove("hidden");
|
||||
document.getElementById("play-icon")!.classList.add("hidden");
|
||||
} else {
|
||||
document.getElementById("pause-icon")!.classList.add("hidden");
|
||||
document.getElementById("play-icon")!.classList.remove("hidden");
|
||||
}
|
||||
|
||||
if (button === "stop") {
|
||||
this.isPlaying == false;
|
||||
document.getElementById("play-label")!.textContent = "Play";
|
||||
document.getElementById("pause-icon")!.classList.add("hidden");
|
||||
document.getElementById("play-icon")!.classList.remove("hidden");
|
||||
}
|
||||
|
||||
this.flashBackground("#404040", 200);
|
||||
const possible_selectors = [
|
||||
'[id^="play-button-"]',
|
||||
'[id^="clear-button-"]',
|
||||
'[id^="stop-button-"]',
|
||||
];
|
||||
let selector: number;
|
||||
switch (button) {
|
||||
case "play":
|
||||
selector = 0;
|
||||
break;
|
||||
case "pause":
|
||||
selector = 1;
|
||||
break;
|
||||
case "clear":
|
||||
selector = 2;
|
||||
break;
|
||||
case "stop":
|
||||
selector = 3;
|
||||
break;
|
||||
}
|
||||
const selectorValue = possible_selectors[selector];
|
||||
if (selectorValue) {
|
||||
document
|
||||
.querySelectorAll(selectorValue)
|
||||
.forEach((button) => {
|
||||
if (highlight && button.children[0]) button.children[0].classList.add("animate-pulse");
|
||||
});
|
||||
}
|
||||
// All other buttons must lose the highlighting
|
||||
document
|
||||
.querySelectorAll(
|
||||
possible_selectors.filter((_, index) => index != selector).join(","),
|
||||
)
|
||||
.forEach((button) => {
|
||||
if (button.children[0]) {
|
||||
button.children[0].classList.remove("animate-pulse");
|
||||
}
|
||||
if (button.children[1]) {
|
||||
button.children[1].classList.remove("animate-pulse");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
unfocusPlayButtons() {
|
||||
document.querySelectorAll('[id^="play-button-"]').forEach((button) => {
|
||||
if (button.children[0]) {
|
||||
button.children[0].classList.remove("fill-foreground_selection");
|
||||
button.children[0].classList.remove("animate-pulse");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateEditorView(): void {
|
||||
this.view.dispatch({
|
||||
changes: {
|
||||
@ -538,14 +457,6 @@ export class Editor {
|
||||
}
|
||||
}
|
||||
|
||||
private initializeButtonGroups(): void {
|
||||
for (const [key, ids] of Object.entries(buttonGroups)) {
|
||||
this.buttonElements[key] = ids.map(
|
||||
(id) => document.getElementById(id) as HTMLButtonElement,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ensureHydraLoaded(): Promise<void> {
|
||||
if (this.hydra_loaded) {
|
||||
return Promise.resolve();
|
||||
|
||||
Reference in New Issue
Block a user