😁 Added too much stuff to explain!
This commit is contained in:
parent
df26cb6ddb
commit
900272a9e1
23 changed files with 899 additions and 58 deletions
src/ts/common/componentManager
|
@ -1,22 +1,222 @@
|
|||
import { Singleton } from "@eix/utils";
|
||||
import { Component } from "../component/component";
|
||||
import { Subject } from "rxjs";
|
||||
import { Component } from "../component";
|
||||
import { Subject, BehaviorSubject, fromEvent } from "rxjs";
|
||||
import { svg, SVGTemplateResult } from "lit-html";
|
||||
import { subscribe } from "lit-rx";
|
||||
import { Screen } from "../screen.ts";
|
||||
import { MnanagerState } from "./interfaces";
|
||||
import { ManagerState } from "./interfaces";
|
||||
import { Store } from "../store";
|
||||
import { KeyboardInput } from "@eix/input"
|
||||
import { success, error } from "toastr"
|
||||
import { ComponentTemplateStore } from "./componentTemplateStore";
|
||||
import { alertOptions } from "./alertOptions";
|
||||
import { WireManager } from "../wires";
|
||||
import { runCounter } from "../component/runCounter";
|
||||
import { Settings } from "../store/settings";
|
||||
import { download } from "./download";
|
||||
|
||||
@Singleton
|
||||
export class ComponentManager {
|
||||
public components: Component[] = []
|
||||
public svgs = new Subject<SVGTemplateResult[]>()
|
||||
public svgs = new Subject<SVGTemplateResult>()
|
||||
public placeholder = new BehaviorSubject("Create simulation")
|
||||
|
||||
private temporaryCommnad = ""
|
||||
private onTop: Component
|
||||
private clicked = false
|
||||
|
||||
private screen = new Screen()
|
||||
private wireManager = new WireManager()
|
||||
private templateStore = new ComponentTemplateStore()
|
||||
private settings = new Settings()
|
||||
|
||||
private commandHistoryStore = new Store<string>("commandHistory")
|
||||
private store = new Store<ManagerState>("simulationStates")
|
||||
|
||||
private saveEvent = new KeyboardInput("s")
|
||||
private createEvent = new KeyboardInput("m")
|
||||
private closeInputEvent = new KeyboardInput("enter")
|
||||
private ctrlEvent = new KeyboardInput("ctrl")
|
||||
private palleteEvent = new KeyboardInput("p")
|
||||
private shiftEvent = new KeyboardInput("shift")
|
||||
private refreshEvent = new KeyboardInput("r")
|
||||
private clearEvent = new KeyboardInput("c")
|
||||
private upEvent = new KeyboardInput("up")
|
||||
private downEvent = new KeyboardInput("down")
|
||||
|
||||
public name = "current"
|
||||
public alertOptions = alertOptions
|
||||
|
||||
private commandHistory: string[] = []
|
||||
private commands: {
|
||||
[key: string]: (ctx: ComponentManager, args: string[], flags: string[]) => any
|
||||
} = {
|
||||
clear(ctx: ComponentManager) {
|
||||
ctx.clear()
|
||||
},
|
||||
save(ctx: ComponentManager) {
|
||||
ctx.save()
|
||||
},
|
||||
ls(ctx: ComponentManager) {
|
||||
const data = ctx.store.ls()
|
||||
const message = data.join("\n")
|
||||
|
||||
success(message, "", ctx.alertOptions)
|
||||
},
|
||||
help(ctx: ComponentManager) {
|
||||
success(`Usage: <command> <br>
|
||||
Where <command> is one of:
|
||||
<ul>
|
||||
${Object.keys(ctx.commands).map(val => `
|
||||
<li>${val}</li>
|
||||
`).join("")}
|
||||
</ul>
|
||||
`, "", ctx.alertOptions)
|
||||
},
|
||||
refresh(ctx: ComponentManager) {
|
||||
ctx.refresh()
|
||||
},
|
||||
ctp: this.templateStore.commands.template,
|
||||
settings: this.settings.commands,
|
||||
download
|
||||
}
|
||||
private inputMode: string
|
||||
|
||||
public barAlpha = new BehaviorSubject<string>("0");
|
||||
|
||||
constructor() {
|
||||
runCounter.increase()
|
||||
|
||||
this.svgs.next(this.render())
|
||||
|
||||
this.refresh()
|
||||
|
||||
fromEvent(document.body, "keydown").subscribe((e: KeyboardEvent) => {
|
||||
if (this.barAlpha.value == "1") {
|
||||
const elem = document.getElementById("nameInput")
|
||||
elem.focus()
|
||||
}
|
||||
else {
|
||||
e.preventDefault()
|
||||
}
|
||||
})
|
||||
|
||||
fromEvent(document.body, "keyup").subscribe((e: MouseEvent) => {
|
||||
if (this.barAlpha.value === "1") {
|
||||
if (this.closeInputEvent.value)
|
||||
this.create()
|
||||
else if (this.inputMode === "command") {
|
||||
const elem = <HTMLInputElement>document.getElementById("nameInput")
|
||||
if (this.upEvent.value) {
|
||||
document.body.focus()
|
||||
e.preventDefault()
|
||||
const index = this.commandHistory.indexOf(elem.value)
|
||||
|
||||
if (index) {
|
||||
//save drafts
|
||||
if (index === -1)
|
||||
this.temporaryCommnad = elem.value
|
||||
|
||||
const newIndex = (index === -1) ? this.commandHistory.length - 1 : index - 1
|
||||
elem.value = this.commandHistory[newIndex]
|
||||
}
|
||||
}
|
||||
if (this.downEvent.value) {
|
||||
document.body.focus()
|
||||
e.preventDefault()
|
||||
const index = this.commandHistory.indexOf(elem.value)
|
||||
|
||||
if (index > -1) {
|
||||
const maxIndex = this.commandHistory.length - 1
|
||||
elem.value = (index === maxIndex) ? this.temporaryCommnad : this.commandHistory[index + 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.ctrlEvent.value) {
|
||||
if (this.createEvent.value) {
|
||||
this.preInput()
|
||||
this.inputMode = "create"
|
||||
this.placeholder.next("Create simulation")
|
||||
}
|
||||
else if (this.shiftEvent.value && this.palleteEvent.value) {
|
||||
this.preInput()
|
||||
this.inputMode = "command"
|
||||
this.placeholder.next("Command palette")
|
||||
}
|
||||
else if (this.clearEvent.value) {
|
||||
this.clear()
|
||||
}
|
||||
else if (this.saveEvent.value) {
|
||||
this.save()
|
||||
}
|
||||
else if (this.refreshEvent.value) {
|
||||
this.refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.wireManager.update.subscribe(val => this.update())
|
||||
}
|
||||
|
||||
preInput() {
|
||||
const elem = <HTMLInputElement>document.getElementById("nameInput")
|
||||
elem.value = ""
|
||||
this.barAlpha.next("1")
|
||||
}
|
||||
|
||||
create() {
|
||||
const elem = <HTMLInputElement>document.getElementById("nameInput")
|
||||
this.barAlpha.next("0")
|
||||
|
||||
if (this.inputMode == "create")
|
||||
success(`Succesfully created simulation ${elem.value}`, "", this.alertOptions)
|
||||
|
||||
else if (this.inputMode == "command")
|
||||
this.eval(elem.value)
|
||||
}
|
||||
|
||||
eval(command: string) {
|
||||
if (!this.commandHistory.includes(command)) // no duplicates
|
||||
this.commandHistory.push(command)
|
||||
|
||||
while (this.commandHistory.length > 10) // max of 10 elements
|
||||
this.commandHistory.shift()
|
||||
|
||||
const words = command.split(" ")
|
||||
|
||||
if (words[0] in this.commands) {
|
||||
const remaining = words.slice(1)
|
||||
const flags = remaining.filter(val => val[0] == "-")
|
||||
const args = remaining.filter(val => val[0] != "-")
|
||||
this.commands[words[0]](this, args, flags)
|
||||
}
|
||||
else
|
||||
error(`Command ${words} doesn't exist. Run help to get a list of all commands.`,
|
||||
"", this.alertOptions)
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.components = []
|
||||
this.wireManager.dispose()
|
||||
this.update()
|
||||
|
||||
success("Succesfully cleared all components", "", this.alertOptions)
|
||||
}
|
||||
|
||||
refresh() {
|
||||
if (this.store.get(this.name)) {
|
||||
this.loadState(this.store.get(this.name))
|
||||
}
|
||||
|
||||
for (const i of this.commandHistoryStore.ls())
|
||||
this.commandHistory[Number(i)] = this.commandHistoryStore.get(i)
|
||||
|
||||
this.update()
|
||||
|
||||
success("Succesfully refreshed to the latest save", "", this.alertOptions)
|
||||
}
|
||||
|
||||
update() {
|
||||
|
@ -64,25 +264,32 @@ export class ComponentManager {
|
|||
render() {
|
||||
let toRemoveDuplicatesFor: Component
|
||||
|
||||
const size = 10
|
||||
const result = this.components.map(component => svg`
|
||||
<rect width=${ subscribe(component.width)}
|
||||
height=${ subscribe(component.height)}
|
||||
x=${ subscribe(component.x)}
|
||||
y=${ subscribe(component.y)}
|
||||
fill="red"
|
||||
stroke="black"
|
||||
@mousedown=${ (e: MouseEvent) => component.handleClick(e)}
|
||||
@mouseup=${ (e: MouseEvent) => {
|
||||
<g>
|
||||
${component.pinsSvg(10, 20)}
|
||||
${component.pinsSvg(10, 20, "output")}
|
||||
|
||||
<rect width=${ subscribe(component.width)}
|
||||
height=${ subscribe(component.height)}
|
||||
x=${ subscribe(component.x)}
|
||||
y=${ subscribe(component.y)}
|
||||
fill="red"
|
||||
stroke="black"
|
||||
rx=20
|
||||
ry=20
|
||||
@mousedown=${ (e: MouseEvent) => component.handleClick(e)}
|
||||
@mouseup=${(e: MouseEvent) => {
|
||||
component.handleMouseUp(e)
|
||||
toRemoveDuplicatesFor = component
|
||||
}}
|
||||
>
|
||||
}}></rect>
|
||||
</g>
|
||||
`);
|
||||
|
||||
if (toRemoveDuplicatesFor)
|
||||
this.removeDuplicates(toRemoveDuplicatesFor)
|
||||
|
||||
return result
|
||||
return svg`${this.wireManager.svg} ${result}`
|
||||
}
|
||||
|
||||
private removeDuplicates(component: Component) {
|
||||
|
@ -95,21 +302,47 @@ export class ComponentManager {
|
|||
.filter((val, index) => instances.indexOf(index) != -1)
|
||||
}
|
||||
|
||||
get state(): MnanagerState {
|
||||
get state(): ManagerState {
|
||||
const components = Array.from((new Set(this.components)).values())
|
||||
return {
|
||||
components: components.map(value => value.state)
|
||||
components: components.map(value => value.state),
|
||||
position: this.screen.position as [number, number],
|
||||
scale: this.screen.scale as [number, number],
|
||||
wires: this.wireManager.state
|
||||
}
|
||||
}
|
||||
|
||||
loadState(state:MnanagerState) {
|
||||
public getComponentById(id: number) {
|
||||
return this.components.find(val => val.id === id)
|
||||
}
|
||||
|
||||
loadState(state: ManagerState) {
|
||||
if (!state.wires) //old state
|
||||
return
|
||||
|
||||
this.wireManager.dispose()
|
||||
this.clicked = false
|
||||
this.components = state.components.map(value => Component.fromState(value))
|
||||
this.onTop = null
|
||||
|
||||
state.wires.forEach(val => {
|
||||
this.wireManager.start = this.getComponentById(val.from.owner).outputPins[val.from.index]
|
||||
this.wireManager.end = this.getComponentById(val.to.owner).inputPins[val.to.index]
|
||||
this.wireManager.tryResolving()
|
||||
})
|
||||
|
||||
this.screen.scale = state.scale
|
||||
this.screen.position = state.position
|
||||
|
||||
this.update()
|
||||
}
|
||||
|
||||
save(){
|
||||
//TODO: implement
|
||||
save(name?: string) {
|
||||
for (let i = 0; i < this.commandHistory.length; i++) {
|
||||
const element = this.commandHistory[i];
|
||||
this.commandHistoryStore.set(i.toString(), element)
|
||||
}
|
||||
this.store.set(name || this.name, this.state)
|
||||
success("Saved the simulation succesfully!", "", this.alertOptions)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue