Compare commits

...

3 Commits

12 changed files with 165 additions and 29 deletions

View File

@ -1,19 +1,40 @@
# MatCat BrowserLogic # MatCat BrowserLogic
MatCat BrowserLogic https://www.logic.parts/ is a logic simulator written purely in HTML5 / Javascript using 2D Canvas. MatCat BrowserLogic https://www.logic.parts/ is a logic simulator written purely in HTML5 / Javascript using 2D Canvas. This code will always work standalone, just download and browse to index.html with your favorite browser.
The goal of this project is to offer a logic simulator that is full featured conceptual simulation of logic. It does not aim to be an electrical simulator, so realistic propagation delays and such are not simulated, however that is not to say that there aren't (as some elements such as clocks and buffers and IC I/O do have delayed buffers).
I designed this to design CPU's in, I am sure someone with some imagination could design nearly anything in it :).
## Status ## Status
This simulator is in extremely early stages, it is not even Alpha at this point but early development. Outside contribution is welcome, please contact me in #LogicParts on Freenode IRC network. Currently, in pre-alpha early dev stage; however the simulator is about to enter the alpha stage, this means that the simulator core functionality is mostly in place. The Alpha stage will be dedicated to polishing the simulator itself, finding and fixing bugs, introduction of local storage for saves, introduction of server storage, and development of the website including adding integration features. Outside contribution is welcome, please contact me (MatCat) in #LogicParts on Freenode IRC network.
## License ## License
To be decided, but at this moment this code is open source and free to use for non-commercial uses. To be decided, but at this moment this code is open source and free to use for non-commercial uses.
Copyright (c) 2021, MatCat
LZ-String, Copyright 2013 pieroxy under MIT license https://github.com/pieroxy/lz-string/blob/master/LICENSE LZ-String, Copyright 2013 pieroxy under MIT license https://github.com/pieroxy/lz-string/blob/master/LICENSE
## Changelog ## Changelog
### 0.4.16
* Fixed bug where properties window didn't disappear at certain times when it should
### 0.4.15
* Prepending ! or ~ (active low) before a pin name will now overline it when displayed on element
* Fixed a bug that disabled a switch after it was disconnected
* Fixed bug in how JK flipflops handled PRE and CLR and CLK
### 0.4.14
* Added WireNode element, allows you to better manage wires. Please note that signals only flow in the direction of connection! It is NOT a bidirectional element
* Added draw speed to FPS display (in uS)
### 0.4.13 ### 0.4.13
* Clicking on an element on the toolbar no longer spawns an element to the work area directly, but rather lets the user place it. * Clicking on an element on the toolbar no longer spawns an element to the work area directly, but rather lets the user place it.

View File

@ -32,25 +32,41 @@ class CanvasTools {
ctx.restore(); ctx.restore();
} }
drawTextCentered(ctx,x,y,x2,y2,text,fontStyle="24px Console",fontColor = "#555") { drawTextCentered(ctx,x,y,x2,y2,text,fontStyle="24px Console",fontColor = "#555", Overline = false) {
ctx.save(); ctx.save();
ctx.font = fontStyle; ctx.font = fontStyle;
ctx.fillStyle = fontColor; ctx.fillStyle = fontColor;
let textSize = this.textSize(ctx,text,fontStyle);
let tHeight = ctx.measureText(text).actualBoundingBoxAscent + ctx.measureText(text).actualBoundingBoxDescent; let tHeight = ctx.measureText(text).actualBoundingBoxAscent + ctx.measureText(text).actualBoundingBoxDescent;
let tX = x+((x2/2)-(ctx.measureText(text).width/2)); let tX = x+((x2/2)-(ctx.measureText(text).width/2));
let tY = y+tHeight+((y2/2)-(tHeight/2)); let tY = y+tHeight+((y2/2)-(tHeight/2));
if (Overline) {
ctx.strokeStyle = fontColor;
ctx.beginPath();
ctx.moveTo(tX,tY-textSize.height-1);
ctx.lineTo(tX+textSize.width,tY-textSize.height-1);
ctx.stroke();
}
ctx.fillText(text,tX,tY); ctx.fillText(text,tX,tY);
ctx.restore(); ctx.restore();
} }
drawText(ctx,x,y,text,fontStyle="24px Console",fontColor = "#555") { drawText(ctx,x,y,text,fontStyle="24px Console",fontColor = "#555",Overline = false) {
let textSize = this.textSize(ctx,text,fontStyle);
ctx.save(); ctx.save();
ctx.font = fontStyle; ctx.font = fontStyle;
ctx.fillStyle = fontColor; ctx.fillStyle = fontColor;
ctx.fillText(text,x,y); ctx.fillText(text,x,y);
if (Overline) {
ctx.strokeStyle = fontColor;
ctx.beginPath();
ctx.moveTo(x,y-textSize.height-2);
ctx.lineTo(x+textSize.width,y-textSize.height-2);
ctx.stroke();
}
ctx.restore(); ctx.restore();
} }
} }
class ContainerConnection { class ContainerConnection {

View File

@ -239,6 +239,7 @@ class Element extends CanvasTools {
this.OutputConnections.splice(a,1); this.OutputConnections.splice(a,1);
a--; a--;
} }
this.Disconnecting = false;
} }
this.drawElement(0,0,this.StaticCtx); this.drawElement(0,0,this.StaticCtx);
} }
@ -354,7 +355,17 @@ class Element extends CanvasTools {
if ((mouseDist <= (this.inputCircleRadius)) && this.LogicEngine.ActiveLink) ctx.fillStyle = circleColorHover; if ((mouseDist <= (this.inputCircleRadius)) && this.LogicEngine.ActiveLink) ctx.fillStyle = circleColorHover;
ctx.fill(); ctx.fill();
ctx.stroke(); ctx.stroke();
if (this.InputLabels[a] && drawFresh) this.drawText(ctx,x+(this.inputCircleRadius*2)+ 5,(firstY + (a*24)) + 5,this.InputLabels[a],"10px Console","#000"); let drawOverline = false;
let label = this.InputLabels[a];
if (this.InputLabels[a] && drawFresh) {
if (this.InputLabels[a].charAt(0) == "!" || this.InputLabels[a].charAt(0) == "~") {
// Draw a NOT line
drawOverline = true;
label = this.InputLabels[a].substring(1);
}
this.drawText(ctx,x+(this.inputCircleRadius*2)+ 5,(firstY + (a*24)) + 5,label,"10px Console","#000",drawOverline);
}
} }
ctx.restore(); ctx.restore();
} }
@ -379,9 +390,18 @@ class Element extends CanvasTools {
ctx.fill(); ctx.fill();
ctx.stroke(); ctx.stroke();
let textSize = false; let textSize = false;
let drawOverline = false;
let label = this.OutputLabels[a];
if (this?.OutputLabels[a]?.charAt(0) == "!" || this?.OutputLabels[a]?.charAt(0) == "~") {
// Draw a NOT line
drawOverline = true;
label = this.OutputLabels[a].substring(1);
}
if (this.OutputLabels[a]) textSize = this.textSize(ctx,this.OutputLabels[a],"10px Console"); if (this.OutputLabels[a]) textSize = this.textSize(ctx,label,"10px Console");
if (this.OutputLabels[a] && drawFresh) this.drawText(ctx,(x+(this.Width)) - (textSize.width + 5 + (this.outputCircleRadius*2)),(firstY + (a*24)) + 5,this.OutputLabels[a],"10px Console","#000"); if (this.OutputLabels[a] && drawFresh) {
this.drawText(ctx,(x+(this.Width)) - (textSize.width + 5 + (this.outputCircleRadius*2)),(firstY + (a*24)) + 5,label,"10px Console","#000",drawOverline);
}
} }
ctx.restore(); ctx.restore();
} }

View File

@ -1,3 +1,28 @@
class LogicWireNode extends Element {
constructor(_Container, RestoreData = null, logicengine) {
super(_Container, RestoreData,logicengine,1);
this.removeProperty("Inputs");
this.Name = "WireNode";
this.Width = 20;
this.Height = 20;
}
getOutput(Output = 0) {
if (Output > 0) return false;
return this.Inputs[0];
}
drawElement(x,y,ctx) {
if (this.LogicEngine.ActiveContainer !== this._Container) return; // No point if we aren't visible
this.StaticCanvas.width = this.Width;
this.StaticCanvas.height = this.Height;
this.drawInputs(ctx,x,y,undefined,undefined,undefined,undefined,true);
this.drawOutputs(ctx,x,y,undefined,undefined,undefined,undefined,true);
}
}
let ElementCatalog_WireNode = new ElementCatalog_Element("WireNode","A simple compact wire node for organizing wiring","-O-",LogicWireNode,[]);
ElementReferenceTable.push(ElementCatalog_WireNode);
ElementCategory_Other.addElement(ElementCatalog_WireNode);
class LogicAND extends Element { class LogicAND extends Element {
constructor(_Container, RestoreData = null, logicengine,Inputs) { constructor(_Container, RestoreData = null, logicengine,Inputs) {
super(_Container, RestoreData,logicengine,Inputs); super(_Container, RestoreData,logicengine,Inputs);

View File

@ -3,11 +3,12 @@ class FlipFlopJK extends Element {
super(_Container, RestoreData,logicengine,5); super(_Container, RestoreData,logicengine,5);
this.Name = "JK-FF"; this.Name = "JK-FF";
this.Outputs = new Array(2); this.Outputs = new Array(2);
this.InputLabels = new Array("J","CLK","K","!PRE", "!CLR"); this.InputLabels = new Array("J","!CLK","K","!PRE", "!CLR");
this.OutputLabels = new Array("Q","~Q"); this.OutputLabels = new Array("Q","~Q");
this.removeProperty("Inputs"); this.removeProperty("Inputs");
this.Height = 140; this.Height = 140;
this.Outputs[0] = true;
this.Outputs[1] = true;
if (RestoreData) { if (RestoreData) {
this.Outputs = RestoreData.OutputStates; this.Outputs = RestoreData.OutputStates;
} }
@ -26,9 +27,12 @@ class FlipFlopJK extends Element {
if (Value !== false) Value = true; if (Value !== false) Value = true;
let oldOutput = this.Outputs[0]; let oldOutput = this.Outputs[0];
let oldOutput2 = this.Outputs[1]; let oldOutput2 = this.Outputs[1];
let oldInput2 = this.Inputs[1];
let oldInput3 = this.Inputs[3];
let oldInput4 = this.Inputs[4];
this.Inputs[Input] = Value; this.Inputs[Input] = Value;
if (this.Inputs[1]) { if (!this.Inputs[1] && oldInput2) {
if (!this.Inputs[0] && this.Inputs[2]) { if (!this.Inputs[0] && this.Inputs[2]) {
// set Q low // set Q low
this.Outputs[0] = false; this.Outputs[0] = false;
@ -43,11 +47,18 @@ class FlipFlopJK extends Element {
this.Outputs[1] = !this.Outputs[0]; this.Outputs[1] = !this.Outputs[0];
} }
} }
if (!this.Inputs[3]) {
if (this.Inputs[4] && !oldInput4 && this.Outputs[0] && this.Outputs[1]) {
this.Outputs[1] = false;
}
if (this.Inputs[3] && !oldInput3 && this.Outputs[0] && this.Outputs[1]) {
this.Outputs[0] = false;
}
if (!this.Inputs[3] && oldInput3) {
this.Outputs[0] = true; this.Outputs[0] = true;
this.Outputs[1] = false; this.Outputs[1] = false;
} }
if (!this.Inputs[4]) { if (!this.Inputs[4] && oldInput4) {
this.Outputs[0] = false; this.Outputs[0] = false;
this.Outputs[1] = true; this.Outputs[1] = true;
} }
@ -105,26 +116,37 @@ class FlipFlopSR extends Element {
if (Value !== false) Value = true; if (Value !== false) Value = true;
let oldOutput = this.Outputs[0]; let oldOutput = this.Outputs[0];
let oldOutput2 = this.Outputs[1]; let oldOutput2 = this.Outputs[1];
let oldInput1 = this.Inputs[1];
let oldInput3 = this.Inputs[3];
let oldInput4 = this.Inputs[4];
this.Inputs[Input] = Value; this.Inputs[Input] = Value;
this.redraw = true; this.redraw = true;
if (this.Inputs[1]) { if (this.Inputs[1] && !oldInput1) {
if (!this.Inputs[0] && this.Inputs[2]) { if (!this.Inputs[0] && this.Inputs[2]) {
// set Q low // set Q low
this.Outputs[0] = false; this.Outputs[0] = false;
this.Outputs[1] = true; this.Outputs[1] = true;
} else if (this.Inputs[0] && !this.Inputs[2]) { } else if (this.Inputs[0] && !this.Inputs[2]) {
// set Q low // set Q high
this.Outputs[0] = true; this.Outputs[0] = true;
this.Outputs[1] = false; this.Outputs[1] = false;
} }
} }
if (!this.Inputs[3]) { if (this.Inputs[4] && !oldInput4 && !this.Inputs[3] && this.Outputs[1]) {
this.Outputs[1] = false;
}
if (this.Inputs[3] && !oldInput3 && !this.Inputs[4] && this.Outputs[0]) {
this.Outputs[0] = false;
}
if (!this.Inputs[3] && oldInput3) {
this.Outputs[0] = true; this.Outputs[0] = true;
this.Outputs[1] = false; this.Outputs[1] = false;
} }
if (!this.Inputs[4]) { if (!this.Inputs[4] && oldInput4) {
this.Outputs[0] = false; this.Outputs[0] = false;
this.Outputs[1] = true; this.Outputs[1] = true;
} }
@ -182,6 +204,8 @@ class FlipFlopT extends Element {
if (Value !== false) Value = true; if (Value !== false) Value = true;
let oldOutput = this.Outputs[0]; let oldOutput = this.Outputs[0];
let oldOutput2 = this.Outputs[1]; let oldOutput2 = this.Outputs[1];
let oldInput2 = this.Inputs[2];
let oldInput3 = this.Inputs[3];
this.Inputs[Input] = Value; this.Inputs[Input] = Value;
this.redraw = true; this.redraw = true;
@ -190,11 +214,11 @@ class FlipFlopT extends Element {
this.Outputs[1] = !this.Outputs[0]; this.Outputs[1] = !this.Outputs[0];
} }
if (!this.Inputs[2]) { if (!this.Inputs[2] && oldInput2) {
this.Outputs[0] = true; this.Outputs[0] = true;
this.Outputs[1] = false; this.Outputs[1] = false;
} }
if (!this.Inputs[3]) { if (!this.Inputs[3] && oldInput3) {
this.Outputs[0] = false; this.Outputs[0] = false;
this.Outputs[1] = true; this.Outputs[1] = true;
} }
@ -254,18 +278,19 @@ class FlipFlopD extends Element {
let oldOutput = this.Outputs[0]; let oldOutput = this.Outputs[0];
let oldOutput2 = this.Outputs[1]; let oldOutput2 = this.Outputs[1];
let oldInput = this.Inputs[1]; let oldInput = this.Inputs[1];
let oldInput2 = this.Inputs[2];
let oldInput3 = this.Inputs[3];
this.Inputs[Input] = Value; this.Inputs[Input] = Value;
this.redraw = true;
if (this.Inputs[1] && !oldInput) { if (this.Inputs[1] && !oldInput) {
this.Outputs[0] = this.Inputs[0]; this.Outputs[0] = this.Inputs[0];
this.Outputs[1] = !this.Outputs[0]; this.Outputs[1] = !this.Outputs[0];
} }
if (!this.Inputs[2]) { if (!this.Inputs[2] && oldInput2) {
this.Outputs[0] = true; this.Outputs[0] = true;
this.Outputs[1] = false; this.Outputs[1] = false;
} }
if (!this.Inputs[3]) { if (!this.Inputs[3] && oldInput3) {
this.Outputs[0] = false; this.Outputs[0] = false;
this.Outputs[1] = true; this.Outputs[1] = true;
} }

View File

@ -78,9 +78,17 @@ class ICInput extends Element {
this.StaticCanvas.width = this.Width; this.StaticCanvas.width = this.Width;
this.StaticCanvas.height = this.Height; this.StaticCanvas.height = this.Height;
let drawOverline = false;
let label = (this.Properties[0].CurrentValue) ? this.Properties[0].CurrentValue.toString() : "";
if (label.charAt(0) == "!" || label.charAt(0) == "~") {
// Draw a NOT line
drawOverline = true;
label = label.substring(1);
}
this.drawBorderBox(ctx,x+10,y,this.Width-30,this.Height); this.drawBorderBox(ctx,x+10,y,this.Width-30,this.Height);
this.drawTextCentered(ctx,x,y+2,this.Width-10,14,this.Designator,"12px Console"); this.drawTextCentered(ctx,x,y+2,this.Width-10,14,this.Designator,"12px Console");
this.drawTextCentered(ctx,x,y,this.Width-10,this.Height,this.Properties[0].CurrentValue,"12px Console"); this.drawTextCentered(ctx,x,y,this.Width-10,this.Height,label,"12px Console",undefined,drawOverline);
this.drawOutputs(ctx,x,y); this.drawOutputs(ctx,x,y);
} }
@ -186,9 +194,17 @@ class ICOutput extends Element {
this.StaticCanvas.width = this.Width; this.StaticCanvas.width = this.Width;
this.StaticCanvas.height = this.Height; this.StaticCanvas.height = this.Height;
let drawOverline = false;
let label = (this.Properties[0].CurrentValue) ? this.Properties[0].CurrentValue.toString() : "";
if (label.charAt(0) == "!" || label.charAt(0) == "~") {
// Draw a NOT line
drawOverline = true;
label = label.substring(1);
}
this.drawBorderBox(ctx,x+20,y,this.Width-10,this.Height); this.drawBorderBox(ctx,x+20,y,this.Width-10,this.Height);
this.drawTextCentered(ctx,x+20,y+2,this.Width-10,14,this.Designator,"12px Console"); this.drawTextCentered(ctx,x+20,y+2,this.Width-10,14,this.Designator,"12px Console");
this.drawTextCentered(ctx,x+20,y,this.Width-10,this.Height,this.Properties[0].CurrentValue,"12px Console"); this.drawTextCentered(ctx,x+20,y,this.Width-10,this.Height,label,"12px Console",undefined,drawOverline);
this.drawInputs(ctx,x,y,undefined,undefined,undefined,undefined,true); this.drawInputs(ctx,x,y,undefined,undefined,undefined,undefined,true);
} }
} }

View File

@ -307,12 +307,11 @@ class InputKeypad extends inputElement {
for (let pX = 0; pX < this.ButtonColumns; pX++) { for (let pX = 0; pX < this.ButtonColumns; pX++) {
this.drawBorderBox(ctx, x + (5*(pX+1))+(buttonWidth*pX), y + (5*(pY+1))+(buttonHeight*pY), buttonWidth, buttonHeight, 1, "#ccc", "#777"); this.drawBorderBox(ctx, x + (5*(pX+1))+(buttonWidth*pX), y + (5*(pY+1))+(buttonHeight*pY), buttonWidth, buttonHeight, 1, "#ccc", "#777");
this.drawTextCentered(ctx,x + (5*(pX+1))+(buttonWidth*pX), y + (5*(pY+1))+(buttonHeight*pY), buttonWidth, buttonHeight, this.Buttons[(pY*this.ButtonColumns) + pX].Text,"16px Console", "#fff"); this.drawTextCentered(ctx,x + (5*(pX+1))+(buttonWidth*pX), y + (5*(pY+1))+(buttonHeight*pY), buttonWidth, buttonHeight, this.Buttons[(pY*this.ButtonColumns) + pX].Text,"16px Console", "#fff");
} }
} }
this.drawTextCentered(ctx,x,y+(this.Height-14),this.Width-(this.outputCircleRadius*2),12,this.Designator,"12px Console","#000"); this.drawTextCentered(ctx,x,y+(this.Height-14),this.Width-(this.outputCircleRadius*2),12,this.Designator,"12px Console","#000");
this.drawOutputs(ctx,x,y); this.drawOutputs(ctx,x,y,undefined,undefined,undefined,undefined,true);
} }
} }

View File

@ -266,6 +266,11 @@ function HideHelp() {
helpWindow.style.display = "none"; helpWindow.style.display = "none";
} }
function HidePropertiesWindow() {
let propwin = document.getElementById("PropertiesBox");
propwin.style.display = "none";
}
function SaveSettings() { function SaveSettings() {
localStorage.setItem("LogicEngineSettings",JSON.stringify(logicEngine.Settings)); localStorage.setItem("LogicEngineSettings",JSON.stringify(logicEngine.Settings));
console.log("Settings Saved"); console.log("Settings Saved");

View File

@ -203,7 +203,7 @@ class LogicEngineSettings {
if (restoresettings) { if (restoresettings) {
let othis = this; let othis = this;
Object.keys(restoresettings).forEach(function(key) { Object.keys(restoresettings).forEach(function(key) {
othis[key] = restoresettings[key]; if (key != "Keybindings") othis[key] = restoresettings[key]; //TODO: Iterate keybindings as well
}); });
} }
} }
@ -653,13 +653,15 @@ class LogicEngine {
let FPSOffset = 5 - this.Panning.OffsetX; let FPSOffset = 5 - this.Panning.OffsetX;
if (this.Settings.ShowFPS) { if (this.Settings.ShowFPS) {
ct.drawText(this.Ctx, FPSOffset, 15 - this.Panning.OffsetY, "FPS: " + this.FPS, "12px console", "#00ff00"); ct.drawText(this.Ctx, FPSOffset, 15 - this.Panning.OffsetY, "FPS: " + this.FPS, "12px console", "#00ff00");
ct.drawText(this.Ctx, FPSOffset, 29 - this.Panning.OffsetY, "Potential FPS: " + Math.floor(this.PotentialFPS), "12px console", "#00ff00"); ct.drawText(this.Ctx, FPSOffset, 29 - this.Panning.OffsetY, "Draw Speed: " + Math.floor(this.frameTimeUS) + "uS", "12px console", "#00ff00");
ct.drawText(this.Ctx, FPSOffset, 43 - this.Panning.OffsetY, "Potential FPS: " + Math.floor(this.PotentialFPS), "12px console", "#00ff00");
} }
let timeCheck = performance.now(); let timeCheck = performance.now();
this.FPSCounter++; this.FPSCounter++;
if (!(Math.round(timeCheck - this.LastFPSCheck) % 50)) { if (!(Math.round(timeCheck - this.LastFPSCheck) % 50)) {
let frameTimeUS = (performance.now() - startLoop) * 1000; let frameTimeUS = (performance.now() - startLoop) * 1000;
this.frameTimeUS = frameTimeUS;
let potentialFPS = 1000000 / frameTimeUS; let potentialFPS = 1000000 / frameTimeUS;
this.PotentialFPSAVGs[this.PotentialFPSAVGLoc] = Math.round(potentialFPS); this.PotentialFPSAVGs[this.PotentialFPSAVGLoc] = Math.round(potentialFPS);
this.PotentialFPSAVGLoc++; this.PotentialFPSAVGLoc++;

View File

@ -2,7 +2,7 @@
MatCat BrowserLogic Simulator MatCat BrowserLogic Simulator
*/ */
let Version = "0.4.13"; let Version = "0.4.16";
let spanVersion = document.getElementById("version"); let spanVersion = document.getElementById("version");
spanVersion.innerText = Version; spanVersion.innerText = Version;

View File

@ -34,12 +34,15 @@ function RightClickMenuListeners() {
logicEngine.Ctx.setTransform(1, 0, 0, 1, 0, 0); logicEngine.Ctx.setTransform(1, 0, 0, 1, 0, 0);
logicEngine.Panning.OffsetX = 0; logicEngine.Panning.OffsetX = 0;
logicEngine.Panning.OffsetY = 0; logicEngine.Panning.OffsetY = 0;
HidePropertiesWindow();
disableSelectedMenus(true);
}); });
let rcm_Delete = document.getElementById("rcm_Delete"); let rcm_Delete = document.getElementById("rcm_Delete");
rcm_Delete.addEventListener('click', function (evt) { rcm_Delete.addEventListener('click', function (evt) {
logicEngine.Key_Press({ctrlKey: false, key: "Delete"}); logicEngine.Key_Press({ctrlKey: false, key: "Delete"});
HidePropertiesWindow();
disableSelectedMenus(true); disableSelectedMenus(true);
}); });

View File

@ -80,6 +80,9 @@ function TopMenuListeners() {
logicEngine.Ctx.setTransform(1, 0, 0, 1, 0, 0); logicEngine.Ctx.setTransform(1, 0, 0, 1, 0, 0);
logicEngine.Panning.OffsetX = 0; logicEngine.Panning.OffsetX = 0;
logicEngine.Panning.OffsetY = 0; logicEngine.Panning.OffsetY = 0;
HidePropertiesWindow();
disableSelectedMenus(true);
setTimeout(function () { setTimeout(function () {
hideMenus() hideMenus()
}, 10); }, 10);
@ -116,6 +119,7 @@ function TopMenuListeners() {
let tfm_Delete = document.getElementById("tfm_Delete"); let tfm_Delete = document.getElementById("tfm_Delete");
tfm_Delete.addEventListener('click', function (evt) { tfm_Delete.addEventListener('click', function (evt) {
logicEngine.Key_Press({ctrlKey: false, key: "Delete"}); logicEngine.Key_Press({ctrlKey: false, key: "Delete"});
HidePropertiesWindow();
disableSelectedMenus(true); disableSelectedMenus(true);
setTimeout(function () { setTimeout(function () {
hideMenus() hideMenus()