feat: finished adding painting features, added eraser
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import TrackUnit, { TrackUnitEvent, TrackUnitStickingType, TrackUnitType } from "@/TrackUnit";
|
||||
import "./TrackUnit.css";
|
||||
import { h, IPublisher, ISubscriber, ISubscription, Publisher, Rung, RungOptions } from "@djledda/ladder";
|
||||
import { Capsule, h, IPublisher, ISubscriber, ISubscription, Publisher, Rung, RungOptions } from "@djledda/ladder";
|
||||
import IconView, { IconName } from "@/ui/Widgets/Icon/IconView";
|
||||
|
||||
export type TrackUnitUINodeOptions = RungOptions & {
|
||||
trackUnit: TrackUnit,
|
||||
@@ -13,7 +14,23 @@ const EventTypeSubscriptions = [
|
||||
];
|
||||
type EventTypeSubscriptions = typeof EventTypeSubscriptions[number];
|
||||
|
||||
export default class TrackUnitView extends Rung<HTMLElement> implements ISubscriber<EventTypeSubscriptions> {
|
||||
export const StickingTypeIconMap = {
|
||||
none: null,
|
||||
lf: 'lf',
|
||||
lh: 'lh',
|
||||
rf: 'rf',
|
||||
rh: 'rh',
|
||||
} as const satisfies Readonly<Record<TrackUnitStickingType, IconName | null>>;
|
||||
|
||||
const TypeClasses = [ "Ghost", "Accent" ] as const;
|
||||
export const TrackUnitTypeClassMap = {
|
||||
"Normal": [],
|
||||
"GhostNote": ["Ghost"],
|
||||
"Accent": ["Accent"],
|
||||
"GhostNoteAccent": ["Ghost", "Accent"],
|
||||
} as const satisfies Readonly<Record<TrackUnitType, Readonly<string[]>>>;
|
||||
|
||||
export default class TrackUnitView extends Rung<HTMLDivElement> implements ISubscriber<EventTypeSubscriptions> {
|
||||
private trackUnit: TrackUnit;
|
||||
private subscription: ISubscription | null = null;
|
||||
private publisher: IPublisher<TrackUnitEvent> = new Publisher<TrackUnitEvent, TrackUnitView>(this);
|
||||
@@ -21,6 +38,7 @@ export default class TrackUnitView extends Rung<HTMLElement> implements ISubscri
|
||||
private mouseDownListeners: ((ev: MouseEvent) => void)[] = [];
|
||||
private hoverListeners: ((ev: MouseEvent) => void)[] = [];
|
||||
private blockNextMouseUp = false;
|
||||
private icon: IconView = new IconView({ iconName: 'list' });
|
||||
|
||||
constructor(options: TrackUnitUINodeOptions) {
|
||||
super(options);
|
||||
@@ -57,12 +75,6 @@ export default class TrackUnitView extends Rung<HTMLElement> implements ISubscri
|
||||
private handleMouseDown(ev: MouseEvent): void {
|
||||
if (ev.button === 1) {
|
||||
this.trackUnit.rotateType();
|
||||
} else {
|
||||
this.rotationTimeout = this.rotationTimeout || setTimeout(() => {
|
||||
this.trackUnit.rotateType();
|
||||
this.blockNextMouseUp = true;
|
||||
this.rotationTimeout = null;
|
||||
}, 400);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,10 +86,6 @@ export default class TrackUnitView extends Rung<HTMLElement> implements ISubscri
|
||||
}
|
||||
|
||||
private handleMouseUp(ev: MouseEvent): void {
|
||||
if (this.rotationTimeout) {
|
||||
clearTimeout(this.rotationTimeout);
|
||||
this.rotationTimeout = null;
|
||||
}
|
||||
if (!this.blockNextMouseUp) {
|
||||
this.mouseDownListeners.forEach(listener => listener(ev));
|
||||
}
|
||||
@@ -103,7 +111,9 @@ export default class TrackUnitView extends Rung<HTMLElement> implements ISubscri
|
||||
}
|
||||
|
||||
setStickingType(type: TrackUnitStickingType): void {
|
||||
this.trackUnit.setStickingType(type);
|
||||
if (this.trackUnit.isOn()) {
|
||||
this.trackUnit.setStickingType(type);
|
||||
}
|
||||
}
|
||||
|
||||
setType(type: TrackUnitType): void {
|
||||
@@ -115,16 +125,17 @@ export default class TrackUnitView extends Rung<HTMLElement> implements ISubscri
|
||||
}
|
||||
|
||||
turnOff(): void {
|
||||
this.trackUnit.setStickingType("none");
|
||||
this.trackUnit.setOn(false);
|
||||
}
|
||||
|
||||
notify(publisher: unknown, event: EventTypeSubscriptions): void {
|
||||
switch (event) {
|
||||
case TrackUnitEvent.On:
|
||||
this.render().classList.add("track-unit-on");
|
||||
this.render().classList.add("on");
|
||||
break;
|
||||
case TrackUnitEvent.Off:
|
||||
this.render().classList.remove("track-unit-on");
|
||||
this.render().classList.remove("on");
|
||||
break;
|
||||
case TrackUnitEvent.TypeChange:
|
||||
this.syncTrackUnitType();
|
||||
@@ -133,43 +144,55 @@ export default class TrackUnitView extends Rung<HTMLElement> implements ISubscri
|
||||
}
|
||||
|
||||
private syncStickingType(type: TrackUnitStickingType) {
|
||||
const node = this.render();
|
||||
node.classList.remove("track-unit-lh");
|
||||
node.classList.remove("track-unit-rh");
|
||||
node.classList.remove("track-unit-lf");
|
||||
node.classList.remove("track-unit-rf");
|
||||
if (type !== "none") {
|
||||
node.classList.add(`track-unit-${ type }`);
|
||||
if (StickingTypeIconMap[this.trackUnit.getStickingType()]) {
|
||||
this.render().classList.add("icon-visible");
|
||||
} else {
|
||||
this.render().classList.remove("icon-visible");
|
||||
}
|
||||
const icon = StickingTypeIconMap[this.trackUnit.getStickingType()];
|
||||
if (icon) {
|
||||
this.icon.setIcon(icon);
|
||||
}
|
||||
}
|
||||
|
||||
private syncTrackUnitType() {
|
||||
switch (this.trackUnit.getType()) {
|
||||
case TrackUnitType.Normal:
|
||||
this.render().classList.remove("track-unit-ghost");
|
||||
this.render().classList.remove("track-unit-accent");
|
||||
break;
|
||||
case TrackUnitType.GhostNote:
|
||||
this.render().classList.add("track-unit-ghost");
|
||||
this.render().classList.remove("track-unit-accent");
|
||||
break;
|
||||
case TrackUnitType.Accent:
|
||||
this.render().classList.remove("track-unit-ghost");
|
||||
this.render().classList.add("track-unit-accent");
|
||||
break;
|
||||
case TrackUnitType.GhostNoteAccent:
|
||||
this.render().classList.add("track-unit-ghost");
|
||||
this.render().classList.add("track-unit-accent");
|
||||
break;
|
||||
for (const className of TypeClasses) {
|
||||
this.render().classList.remove(className);
|
||||
}
|
||||
for (const className of TrackUnitTypeClassMap[this.trackUnit.getType()]) {
|
||||
this.render().classList.add(className);
|
||||
}
|
||||
}
|
||||
|
||||
build(): HTMLElement {
|
||||
static getClasses(options: { on: boolean, stickingType: TrackUnitStickingType, type: TrackUnitType, highlightable?: boolean }) {
|
||||
const classes = ["track-unit"];
|
||||
if (this.trackUnit.isOn()) {
|
||||
classes.push("track-unit-on");
|
||||
if (options.on) {
|
||||
classes.push("on");
|
||||
}
|
||||
return <div classes={classes} oncontextmenu={() => false} /> as HTMLElement;
|
||||
if (StickingTypeIconMap[options.stickingType]) {
|
||||
classes.push("icon-visible");
|
||||
}
|
||||
if (options.type) {
|
||||
classes.push(...TrackUnitTypeClassMap[options.type]);
|
||||
}
|
||||
if (options.highlightable) {
|
||||
classes.push("highlightable");
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
build() {
|
||||
const classes = TrackUnitView.getClasses({
|
||||
on: this.trackUnit.isOn(),
|
||||
stickingType: this.trackUnit.getStickingType(),
|
||||
type: this.trackUnit.getType(),
|
||||
highlightable: true,
|
||||
});
|
||||
return (
|
||||
<div classes={classes} oncontextmenu={() => false}>
|
||||
{this.icon}
|
||||
</div>
|
||||
) as HTMLDivElement;
|
||||
}
|
||||
|
||||
onHover(cb: () => void): void {
|
||||
|
||||
Reference in New Issue
Block a user