feat: finished adding painting features, added eraser

This commit is contained in:
Daniel Ledda
2023-01-04 12:35:02 +01:00
parent bcdebd3372
commit 59f48c8398
11 changed files with 506 additions and 440 deletions

View File

@@ -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 {