ProzillaOS/packages/apps/logic-sim/core/chips/chip.ts
2024-06-16 21:46:44 +02:00

176 lines
No EOL
4.5 KiB
TypeScript

import { CHIP, COLORS, PIN } from "../../../../config/apps/logicSim.config";
import { Vector2 } from "../../../math/vector2";
import { Circuit } from "../circuit";
import { Pin, PinJson } from "../pins/pin";
import { State } from "../_utils/state";
export interface ChipJson {
color: string;
name: string;
position: {
x: number;
y: number;
};
inputPins: PinJson[];
outputPins: PinJson[];
}
export class Chip {
color!: string;
name!: string;
position = Vector2.ZERO;
size!: Vector2;
circuit!: Circuit;
isCircuit = false;
isBlueprint = false;
inputCount = 0;
outputCount = 0;
inputPins!: Pin[];
outputPins!: Pin[];
logic!: (inputStates: State[]) => State[];
constructor(circuit: Circuit | null, name: string, color: string, isBlueprint: boolean, inputCount: number, outputCount: number) {
Object.assign(this, { circuit, name, color, isBlueprint, inputCount, outputCount });
if (this.circuit == null && !isBlueprint) {
this.circuit = this as unknown as Circuit;
this.isCircuit = true;
}
if (this.isCircuit || this.isBlueprint)
return;
if (this.circuit != null) {
const textRect = this.circuit.getTextRect(CHIP.fontSize, this.name);
const width = textRect.x + (CHIP.padding + CHIP.BorderWidth) * 2;
const minHeight = textRect.y + (CHIP.padding + CHIP.BorderWidth) * 2;
this.size = new Vector2(width, minHeight);
}
this.inputPins = [];
for (let i = 0; i < inputCount; i++) {
const newPin = new Pin(this.circuit, "IN " + i, true, this);
this.inputPins.push(newPin);
if (this.isCircuit)
newPin.isControlled = true;
}
this.outputPins = [];
for (let i = 0; i < outputCount; i++) {
const newPin = new Pin(this.circuit, "OUT " + i, false, this);
this.outputPins.push(newPin);
if (this.isCircuit)
newPin.isControlled = true;
}
}
setCircuit(circuit: Circuit) {
this.circuit = circuit;
this.inputPins.concat(this.outputPins).forEach((pin) => { pin.circuit = circuit; });
}
setLogic(logic: (inputStates: State[]) => State[]) {
this.logic = logic;
return this;
}
update() {
if (this.logic == null)
return;
const inputStates: State[] = [];
for (let i = 0; i < this.inputCount; i++) {
const state = this.inputPins[i].state ?? State.LOW;
inputStates.push(state);
}
const outputStates: State[] = this.logic(inputStates);
for (let i = 0; i < this.outputCount; i++) {
this.outputPins[i].setState(outputStates[i]);
}
}
drawPins(reposition = true) {
this.inputPins.forEach((pin, index) => {
if (reposition) {
const gap = (this.size.y - this.inputCount * PIN.radius * 2) / (this.inputCount + 1);
pin.position.x = this.position.x;
pin.position.y = this.position.y + gap * (index + 1) + PIN.radius * (2 * index + 1);
}
const isPlacingPin = this.circuit.inputHandler.isPlacingPin(pin, index);
pin.draw(isPlacingPin);
});
this.outputPins.forEach((pin, index) => {
if (reposition) {
const gap = (this.size.y - this.outputCount * PIN.radius * 2) / (this.outputCount + 1);
pin.position.x = this.position.x + this.size.x;
pin.position.y = this.position.y + gap * (index + 1) + PIN.radius * (2 * index + 1);
}
const isPlacingPin = this.circuit.inputHandler.isPlacingPin(pin, index);
pin.draw(isPlacingPin);
});
}
draw(isPlacing: boolean) {
this.circuit.drawRect(
this.circuit.getColor(this.color + "-1"),
this.position.x, this.position.y,
this.size.x, this.size.y
);
this.circuit.drawRect(
this.circuit.getColor(this.color + "-0"),
this.position.x + CHIP.BorderWidth, this.position.y + CHIP.BorderWidth,
this.size.x - CHIP.BorderWidth * 2, this.size.y - CHIP.BorderWidth * 2
);
this.circuit.drawText(
this.circuit.getColor(COLORS.chip.text),
"center",
this.position.x + this.size.x / 2, this.position.y + this.size.y / 2,
CHIP.fontSize,
this.name
);
if (isPlacing) {
this.circuit.setDrawingOpacity(0.25);
this.circuit.drawRect(
this.circuit.getColor(COLORS.chip.outline),
this.position.x - CHIP.placingOutline, this.position.y - CHIP.placingOutline,
this.size.x + CHIP.placingOutline * 2, this.size.y + CHIP.placingOutline * 2
);
this.circuit.resetDrawingOpacity();
}
this.drawPins();
}
toJson(): ChipJson {
const object = {
color: this.color,
name: this.name,
position: {
x: this.position.x,
y: this.position.y
},
} as ChipJson;
if (this.inputPins.length > 0)
object.inputPins = this.inputPins.map((pin) => pin.toJson());
if (this.outputPins.length > 0)
object.outputPins = this.outputPins.map((pin) => pin.toJson());
return object;
}
}