newlogic
Version:
Circuit Builder Desktop Application (like mmlogic) made with Electron + React Typescript. Compatible with Windows, Mac and Linux.
188 lines (161 loc) • 6.88 kB
text/typescript
import Workspace from "../components/Workspace";
import GateNode from "../gates/Node";
import { AnyGate, GateCoords, GateGeneric, GateSize } from "../interfaces/canvas";
import { IContext } from "../interfaces/components";
import { Wire } from "../gates";
export namespace Wiring {
export function cutDraw(ctx: CanvasRenderingContext2D, init: GateCoords, coords: GateCoords): void {
ctx.moveTo(init.x, init.y);
ctx.lineTo(coords.x, coords.y);
ctx.strokeStyle = "#777";
ctx.lineWidth = 1.5;
ctx.stroke();
}
export function cutIntersect(coords: GateCoords, wires: Wire[]): number {
for (let i in wires) {
// https://web.archive.org/web/20060911055655/http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
let wire = wires[i];
// Line 1
let c1 = wire.state.startNode.getCoords();
let c2 = wire.state.break;
coords = {x: Math.round(coords.x), y: Math.round(coords.y)};
// console.log(c1, c2, coords);
if (Math.abs(c1.x - coords.x) <= 10 && coords.y >= c1.y && coords.y <= c2.y) {
return parseInt(i);
}
c1 = wire.state.endNode.getCoords();
if (Math.abs(c1.y - coords.y) <= 10 && coords.x >= c2.x && coords.x <= c1.x) {
return parseInt(i);
}
}
return -1;
}
export function wireSnap(nodes: GateNode<any>[], coords: GateCoords, snap: number): GateNode<any> | null {
for (let node of nodes) {
const nodeCoords = node.getCoords();
if (Math.abs(coords.x - nodeCoords.x) <= snap && Math.abs(coords.y - nodeCoords.y) <= snap) {
return node;
}
}
return null;
}
export function rerender<T extends GateGeneric>(obj: T[], ctx: CanvasRenderingContext2D | null): void {
for (let i of obj) {
if (!!i.state && ctx !== null) i.render(ctx);
else if (!!i.state) i.render();
}
}
export function isClicked<T extends GateGeneric>(obj: T[], coords: GateCoords): T | null {
for (let gate of obj) {
const size = gate.state.size;
const gatecoords = gate.state.coords;
if (coords.x >= gatecoords.x && coords.x <= gatecoords.x + size.width &&
coords.y >= gatecoords.y && coords.y <= gatecoords.y + size.height) {
return gate;
}
}
return null;
}
export function otherGates(coords: GateCoords, gates: AnyGate[], size: GateSize = {width: 40, height: 40}): boolean {
for (let gate of gates) {
if ((coords.x >= gate.state.coords.x && coords.x <= gate.state.coords.x + gate.state.size.width &&
coords.y >= gate.state.coords.y && coords.y <= gate.state.coords.y + gate.state.size.height) ||
(coords.x >= gate.state.coords.x - size.width && coords.x <= gate.state.coords.x + gate.state.size.width - size.width &&
coords.y >= gate.state.coords.y - size.height && coords.y <= gate.state.coords.y + gate.state.size.height - size.height)) {
return true;
}
}
return false;
}
export function renderNodes(nodes: GateNode<any>[], ctx: CanvasRenderingContext2D): void {
for (let i of nodes) {
i.render(ctx);
}
}
export function drawWire(ctx: CanvasRenderingContext2D, init: GateCoords, current: GateCoords): GateCoords {
ctx.beginPath();
// Normalise for horizontal/vertical drawing
let breakpoint: GateCoords = {
y: (current.y),
x: (init.x)
}
ctx.moveTo(init.x, init.y);
ctx.lineTo(breakpoint.x, breakpoint.y);
ctx.lineTo(current.x, current.y);
ctx.strokeStyle = "#333";
ctx.lineWidth = 3;
ctx.stroke();
return breakpoint;
}
export function selection(ctx: CanvasRenderingContext2D, init: GateCoords, curent: GateCoords): void {
// ctx.beginPath();
}
export function gridLayout(coords: GateCoords, factor: number): GateCoords {
let x: number, y: number;
x = Math.ceil(coords.x / factor) * factor;
y = Math.ceil(coords.y / factor) * factor;
return { x, y }
}
export function renderContext(ctx: CanvasRenderingContext2D, obj: IContext): void {
// Render background
ctx.fillStyle = '#222222';
ctx.strokeStyle = "rgba(20,20,20,.1)";
ctx.lineWidth = 1;
ctx.fillRect(obj.coords.x, obj.coords.y, obj.size.width, obj.size.height);
ctx.strokeRect(obj.coords.x, obj.coords.y, obj.size.width, obj.size.height);
// Render text
ctx.fillStyle = "white";
ctx.font = "15px PT_Sans";
ctx.lineWidth = .7;
let x = obj.coords.x + 5;
let y = obj.coords.y + 15;
for (let text of obj.options) {
ctx.fillText(text, x, y+2, obj.size.width - 5);
y += 15;
}
ctx.strokeStyle = "black";
ctx.lineWidth = 3;
}
export function contextClicked(coords: GateCoords, obj: IContext): boolean {
let gatecoords = obj.coords;
let size = obj.size;
if (coords.x >= gatecoords.x && coords.x <= gatecoords.x + size.width &&
coords.y >= gatecoords.y && coords.y <= gatecoords.y + size.height) {
return true;
}
return false;
}
export function contextHover(y: number, obj: IContext, ctx: CanvasRenderingContext2D): string {
if (y > obj.coords.y + 5 && y < obj.coords.y + obj.size.height + 5) {
let i = Math.ceil(((y - obj.coords.y) / (obj.size.height) * obj.options.length));
console.log(i-1);
let renderY = obj.coords.y + 5 + 15*(i-1);
ctx.fillStyle = "#000000";
ctx.fillRect(obj.coords.x, renderY, obj.size.width, 15);
// Render text
ctx.fillStyle = "white";
ctx.lineWidth = .7;
ctx.fillText(obj.options[i-1], obj.coords.x + 5, obj.coords.y + 15*(i) + 2, obj.size.width - 5);
ctx.strokeStyle = "black";
ctx.lineWidth = 3;
// Return str
return obj.options[i-1];
}
return "";
}
export function contextActions(workspace: Workspace, gate: AnyGate, option: string): void {
if (!gate.checkCustomContext(option)) {
switch (option) {
case "Properties":
workspace.propertyWindow(gate);
break;
case "Delete":
workspace.deleteGate(gate.state.id);
break;
}
} else {
workspace.clear();
workspace.onChange();
}
}
}