BrowserLogic/js/globalfunctions.js

570 lines
21 KiB
JavaScript

function addElement(RestoreData = null,refClass,props) {
let newElement = new refClass(logicEngine.ActiveContainer,RestoreData,logicEngine,...props);
if (!RestoreData) {
let x = Math.round(logicEngine.Canvas.width / 2) - (newElement.Width/2);
let y = Math.round(logicEngine.Canvas.height / 2) - (newElement.Height/2);
x -= logicEngine.Panning.OffsetX;
y -= logicEngine.Panning.OffsetY;
x = logicEngine.Settings.GridSize * Math.round(x/logicEngine.Settings.GridSize);
y = logicEngine.Settings.GridSize * Math.round(y/logicEngine.Settings.GridSize);
let width = newElement.Width;
let height = newElement.Height;
let noclearspot = true;
let findattempt = 0;
while (noclearspot && findattempt < 100) {
findattempt++;
if (!logicEngine.ActiveContainer.checkOverlayBounds(x, y, width, height)) {
noclearspot = false;
} else {
x += Math.floor(Math.random() * (width - (width - (width * 2)))) + (width - (width * 2));
y += Math.floor(Math.random() * (height - (height - (height * 2)))) + (height - (height * 2));
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x + width > logicEngine.Canvas.width) x = logicEngine.Canvas.width - width;
if (y + height > logicEngine.Canvas.height) y = logicEngine.Canvas.height - height;
x = logicEngine.Settings.GridSize * Math.round(x/logicEngine.Settings.GridSize);
y = logicEngine.Settings.GridSize * Math.round(y/logicEngine.Settings.GridSize);
}
}
newElement.X = x;
newElement.Y = y;
}
logicEngine.ActiveContainer.AddElement(newElement);
logicEngine.ActiveContainer.Select(newElement);
disableSelectedRCMs(false);
return newElement;
}
function createIC(container,name,description) {
let newContainer = false;
if (container instanceof elementContainer) newContainer = loadContainer(JSON.parse(JSON.stringify(container)));
if (typeof container == 'string' || container instanceof String) newContainer = loadContainer(JSON.parse(container));
if (!newContainer) return false;
let ICSettings = {
Name: name.replace('^[a-zA-Z0-9_]+$',''),
Description: description,
Container: JSON.stringify(container),
};
let outputCount = 0;
for (let a = 0; a < newContainer.Elements.length; a++) {
if (newContainer.Elements[a] instanceof ICOutput) {
outputCount++;
}
}
if (outputCount == 0) return false;
let ElementCatalog_IC = new ElementCatalog_Element(ICSettings.Name,ICSettings.Description,"≡█≡",ICElement,[ICSettings]);
ElementReferenceTable.push(ElementCatalog_IC);
ElementCategory_ICs.addElement(ElementCatalog_IC);
BuildToolbox();
return ElementCatalog_IC;
}
function setCookie(cname, cvalue, exdays) {
let d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
let expires = "expires="+ d.toUTCString();
document.cookie = cname + '="' + cvalue + '";' + expires;
localStorage.setItem(cname,cvalue);
}
function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(';');
for(var i = 0; i <ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return localStorage.getItem(cname);
}
function CheckForWelcomeCookie() {
if (getCookie("hidewelcomescreen")) {
let WelcomeScreen = document.getElementById("WelcomeWindow");
let DarkOverlay = document.getElementById("darkout-overlay");
WelcomeScreen.style.display = "none";
DarkOverlay.style.display = "none";
}
}
function getMousePos(canvas, evt) {
let rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
function averageArray(arr) {
return arr.reduce((a, b) => (a + b)) / arr.length;
}
function length2D(x1,y1,x2,y2) {
let xDist = x1 - x2;
let yDist = y1 - y2;
return Math.sqrt(xDist*xDist + yDist * yDist);
}
function MatchesPress(binding,evt) {
let retval = true;
if (binding?.Key == evt.key.toLowerCase()) {
if (binding?.Alt) {
if (!evt.altKey) retval = false;
} else {
if (evt.altKey) retval = false;
}
if (binding?.Ctrl) {
if (!evt.ctrlKey) retval = false;
} else {
if (evt.ctrlKey) retval = false;
}
if (binding?.Shift) {
if (!evt.shiftKey) retval = false;
} else {
if (evt.shiftKey) retval = false;
}
if (binding?.Meta) {
if (!evt.metaKey) retval = false;
} else {
if (evt.metaKey) retval = false;
}
} else {
retval = false;
}
return retval;
}
function KeybindToString(binding) {
let kbs = "";
if (binding?.Meta) kbs += "Meta+";
if (binding?.Ctrl) kbs += "Ctrl+";
if (binding?.Alt) kbs += "Alt+";
if (binding?.Shift) kbs += "Shift+";
kbs += binding?.Key.toUpperCase();
return kbs;
}
function GetCopyObject() {
if (logicEngine?.ActiveContainer?.Selected?.length > 0) {
let copyObject = {Paste: true,LogicParts: Version};
copyObject.Elements = logicEngine.ActiveContainer.Selected;
let copyObjectString = JSON.stringify(copyObject);
copyObject = JSON.parse(copyObjectString);
for (let a = 0; a < copyObject.Elements.length; a++) {
console.log("Adaptering X: " + copyObject.Elements[a].X + " to " + (copyObject.Elements[a].X + logicEngine.Panning.OffsetX));
console.log("Adaptering Y: " + copyObject.Elements[a].Y + " to " + (copyObject.Elements[a].Y + logicEngine.Panning.OffsetY));
copyObject.Elements[a].X = copyObject.Elements[a].X + logicEngine.Panning.OffsetX;
copyObject.Elements[a].Y = copyObject.Elements[a].Y + logicEngine.Panning.OffsetY;
}
return copyObject;
} else {
return false;
}
}
function BuildTopMenu() {
// Make sure settings are set correct
if (logicEngine.Settings.HideConnections) {
let sgSpan = tfm_ShowConns.getElementsByClassName("checkbox")[0];
sgSpan.innerHTML = "&nbsp;";
} else {
let sgSpan = tfm_ShowConns.getElementsByClassName("checkbox")[0];
sgSpan.innerText = "✓";
}
if (!logicEngine.Settings.TopConnections) {
tfm_ConnLayer.innerHTML = '<span class="blankbox">&nbsp;</span>Connections Above';
} else {
tfm_ConnLayer.innerHTML = '<span class="blankbox">&nbsp;</span>Connections Below';
}
if (!logicEngine.Settings.ShowFPS) {
let sgSpan = tfm_ShowFPS.getElementsByClassName("checkbox")[0];
sgSpan.innerHTML = "&nbsp;";
} else {
let sgSpan = tfm_ShowFPS.getElementsByClassName("checkbox")[0];
sgSpan.innerText = "✓";
}
if (!logicEngine.Settings.ShowGrid) {
let sgSpan = tfm_ShowGrid.getElementsByClassName("checkbox")[0];
sgSpan.innerHTML = "&nbsp;";
} else {
let sgSpan = tfm_ShowGrid.getElementsByClassName("checkbox")[0];
sgSpan.innerText = "✓";
}
if (!logicEngine.Settings.SnapGrid) {
let sgSpan = tfm_SnapGrid.getElementsByClassName("checkbox")[0];
sgSpan.innerHTML = "&nbsp;";
} else {
let sgSpan = tfm_SnapGrid.getElementsByClassName("checkbox")[0];
sgSpan.innerText = "✓";
}
in_GridSize.value = logicEngine.Settings.GridSize;
}
function BuildToolbox() {
let toolbox = document.getElementById("inner-left-menu");
toolbox.innerHTML = "";
for (let a = 0; a < elementCatalog.Categories.length; a++) {
let div_CategoryHeader = document.createElement("div");
div_CategoryHeader.id = "TB_CATH_" + elementCatalog.Categories[a].Name;
div_CategoryHeader.className ="TOOLBOX_CATEGORY_HEADER";
div_CategoryHeader.innerHTML = '<h2>' + elementCatalog.Categories[a].Name + '</h2>';
let div_Category = document.createElement("div");
div_Category.id = "TB_CATB_" + elementCatalog.Categories[a].Name;
div_Category.className = "TOOLBOX_CATEGORY_BODY";
div_Category.innerHTML = "";
for (let b = 0; b < elementCatalog.Categories[a].Elements.length; b++) {
let btn_Element = document.createElement("input");
btn_Element.type = "button";
btn_Element.id = "btn_" + elementCatalog.Categories[a].Elements[b].Name;
btn_Element.title = elementCatalog.Categories[a].Elements[b].Description;
btn_Element.value = elementCatalog.Categories[a].Elements[b].Icon + " " + elementCatalog.Categories[a].Elements[b].Name;
btn_Element.style.width = "100px";
btn_Element.style.textAlign = "left";
btn_Element.addEventListener('click', function(evt) {
addElement(null,elementCatalog.Categories[a].Elements[b].Class,elementCatalog.Categories[a].Elements[b].Args);
}, false);
div_Category.append(btn_Element);
// div_Category.append(document.createElement("br"));
}
toolbox.append(div_CategoryHeader);
toolbox.append(div_Category);
}
}
function getElementInfo(element) {
for (let a = 0; a < ElementReferenceTable.length; a++) {
if (ElementReferenceTable[a].Name == element) return ElementReferenceTable[a];
}
return false;
}
function isVersionNewer(version1,version2,orEqual = true) {
let v1 = version1.split(".");
let v2 = version1.split(".");
if (v1.length != 3) return false;
if (v2.length != 3) return false;
for (let a = 0; a < 3; a++) {
v1[a] = parseInt(v1[a]);
v2[a] = parseInt(v2[a]);
}
if (v1[0] > v2[0]) return true;
if (v1[0] == v2[0] && v1[1] > v2[1]) return true;
if (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] > v2[2]) return true;
if ((v1[0] == v2[0] && v1[1] == v2[1]) && (orEqual && v1[2] == v2[2])) return true;
return false;
}
function disableSelectedRCMs(bool) {
let rcm_Delete = document.getElementById("rcm_Delete");
let rcm_Disconnect = document.getElementById("rcm_Disconnect");
let tfm_Delete = document.getElementById("tfm_Delete");
let tfm_Disconnect = document.getElementById("tfm_Disconnect");
if (bool) {
rcm_Delete.classList.add("disabled");
rcm_Disconnect.classList.add("disabled");
tfm_Delete.classList.add("disabled");
tfm_Disconnect.classList.add("disabled");
} else {
rcm_Delete.classList.remove("disabled");
rcm_Disconnect.classList.remove("disabled");
tfm_Delete.classList.remove("disabled");
tfm_Disconnect.classList.remove("disabled");
}
}
function showRCM(evt) {
evt.preventDefault();
let rcm = document.getElementById("RightClickMenu");
rcm.style.left = (evt.clientX-40) + "px";
rcm.style.top = (evt.clientY-25) + "px";
rcm.style.display = "block";
}
function ShowHelp() {
let helpWindow = document.getElementById("HelpWindow");
helpWindow.style.display = "block";
helpWindow.style.left = Math.round((window.innerWidth / 2) - (helpWindow.clientWidth/2)) + "px";
helpWindow.style.top = Math.round((window.innerHeight / 2) - (helpWindow.clientHeight/2)) + "px";
}
function HideHelp() {
let helpWindow = document.getElementById("HelpWindow");
helpWindow.style.display = "none";
}
function hideMenus() {
let tds = document.getElementsByClassName("top-menu-div");
for (let a = 0; a < tds.length; a++) {
tds[a].setAttribute('style','display: none;');
}
}
function SaveSettings() {
localStorage.setItem("LogicEngineSettings",JSON.stringify(logicEngine.Settings));
console.log("Settings Saved");
}
function createSaveState(container = false) {
let saveState = {
Name: "LogicDesign",
Version: Version,
Timestamp: Date.now(),
PanX: logicEngine.Panning.OffsetX,
PanY: logicEngine.Panning.OffsetY,
Elements: new Array()
};
if (container.Elements.length > 0) saveState.Elements = container.Elements;
let saveCompressed = document.getElementById("saveCompressed");
if (saveCompressed.checked) {
saveState.Elements = LZString.compressToUTF16(JSON.stringify(saveState.Elements));
saveState.Compressed = true;
} else {
saveState.Compressed = false;
}
return saveState;
}
function download(filename, savestate) {
let text = JSON.stringify(savestate);
let element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
function getPastedElementDesignator(map,element) {
for (let a = 0; a < map?.length; a++) {
if (map[a].Old == element) return map[a].New;
}
return false;
}
function loadActiveContainer(Elements) {
let elementConnections = new Array();
let icelementConnections = new Array();
let designatorMap = new Array();
let selectedObjects = new Array();
let lowestX = 9999999999;
let lowestY = 9999999999;
let highestX = 0;
let highestY = 0;
for (let a = 0; a < Elements.length; a++) {
if (Elements[a].IsIC) {
let classRef = getElementInfo(Elements[a].Name).Class;
if (!classRef) {
// We need to add this IC to the toolbox
let newIC = createIC(JSON.stringify(Elements[a].ICBlueprint),Elements[a].Name,Elements[a].Description);
//console.log("NewIC:" + newIC);
if (!newIC) return false;
}
}
let classRef = getElementInfo(Elements[a].Name).Class;
let newElement = new classRef(logicEngine.ActiveContainer,Elements[a],logicEngine,getElementInfo(Elements[a].Name).Args[0]);
if (newElement) selectedObjects.push(newElement);
logicEngine.ActiveContainer.AddElement(newElement);
newElement.X -= logicEngine.Panning.OffsetX;
newElement.Y -= logicEngine.Panning.OffsetY;
if (newElement.X < lowestX) lowestX = newElement.X;
if (newElement.X > highestX) highestX = newElement.X;
if (newElement.Y < lowestY) lowestY = newElement.Y;
if (newElement.Y > highestY) highestY = newElement.Y;
designatorMap.push({Old: Elements[a].Designator, New: newElement.Designator});
if (Elements[a].Outputs) {
if (Elements[a].Outputs.length > 0) {
for (let b=0; b < Elements[a].Outputs.length; b++) {
elementConnections.push({
FromElement: newElement,
Input: Elements[a].Outputs[b].Input,
Output: Elements[a].Outputs[b].Output,
ToElement: Elements[a].Outputs[b].Element
});
}
}
}
if (Elements[a].ICOutputs) {
if (Elements[a].ICOutputs.length > 0) {
for (let b=0; b < Elements[a].ICOutputs.length; b++) {
icelementConnections.push({
Element: newElement,
FromContainer: newElement.Container,
FromElement: Elements[a].ICOutputs[b].fromElement,
Input: Elements[a].ICOutputs[b].Input,
ToElement: Elements[a].ICOutputs[b].toElement
});
}
}
}
}
logicEngine.ActiveContainer.Selected = selectedObjects;
logicEngine.MovingElement = new Array(logicEngine.ActiveContainer.Selected.length);
for (let b = 0; b < logicEngine.ActiveContainer.Selected.length; b++) {
logicEngine.ActiveContainer.Selected[b].X = (logicEngine.ActiveContainer.Selected[b].X - lowestX) + (logicEngine.Mouse.x - logicEngine.Panning.OffsetX) - ((highestX-lowestX)/2);
logicEngine.ActiveContainer.Selected[b].Y = (logicEngine.ActiveContainer.Selected[b].Y - lowestY) + (logicEngine.Mouse.y - logicEngine.Panning.OffsetY) - ((highestY-lowestY)/2);
logicEngine.MovingElement[b] = {
StartX: logicEngine.ActiveContainer.Selected[b].X,
StartY: logicEngine.ActiveContainer.Selected[b].Y
};
logicEngine.MovingElementMouseStartX = logicEngine.Mouse.x;
logicEngine.MovingElementMouseStartY = logicEngine.Mouse.y;
}
logicEngine.MouseDown = true;
for (let a = 0; a < elementConnections.length; a++) {
let toElement = logicEngine.ActiveContainer.HasElement(getPastedElementDesignator(designatorMap,elementConnections[a].ToElement));
if (toElement) {
if (elementConnections[a].FromContainer) {
let fromElement = elementConnections[a].FromContainer.HasElement(elementConnections[a].fromElement);
let newConnection = new ContainerConnection(elementConnections[a].FromContainer,logicEngine.ActiveContainer,fromElement,toElement,elementConnections[a].Input);
elementConnections[a].Element.Outputs.push(newConnection);
} else {
let newConnection = new ElementConnection(logicEngine.ActiveContainer, toElement, elementConnections[a].Input, elementConnections[a].Output);
if (newConnection) {
elementConnections[a].FromElement.addConnection(logicEngine.ActiveContainer,toElement,elementConnections[a].Input, elementConnections[a].Output)
} else {
console.log("We dont have a new connection!!!");
console.log(toElement);
console.log(elementConnections[a]);
}
}
}
}
}
function loadContainer(Elements) {
let newContainer = new elementContainer();
let elementConnections = new Array();
let icelementConnections = new Array();
for (let a = 0; a < Elements.length; a++) {
if (Elements[a].IsIC) {
let classRef = getElementInfo(Elements[a].Name).Class;
if (!classRef) {
// We need to add this IC to the toolbox
let newIC = createIC(JSON.stringify(Elements[a].ICBlueprint),Elements[a].Name,Elements[a].Description);
//console.log("NewIC:" + newIC);
if (!newIC) return false;
}
}
let classRef = getElementInfo(Elements[a].Name).Class;
let newElement = new classRef(newContainer,Elements[a],logicEngine,getElementInfo(Elements[a].Name).Args[0]);
newContainer.AddElement(newElement);
newElement.Designator = Elements[a].Designator;
if (Elements[a].Outputs) {
if (Elements[a].Outputs.length > 0) {
for (let b=0; b < Elements[a].Outputs.length; b++) {
elementConnections.push({
FromElement: newElement,
Input: Elements[a].Outputs[b].Input,
Output: Elements[a].Outputs[b].Output,
ToElement: Elements[a].Outputs[b].Element
});
}
}
}
if (Elements[a].ICOutputs) {
if (Elements[a].ICOutputs.length > 0) {
for (let b=0; b < Elements[a].ICOutputs.length; b++) {
icelementConnections.push({
Element: newElement,
FromContainer: newElement.Container,
FromElement: Elements[a].ICOutputs[b].fromElement,
Input: Elements[a].ICOutputs[b].Input,
ToElement: Elements[a].ICOutputs[b].toElement
});
}
}
}
}
// Now we need to make all of the connections
for (let a = 0; a < elementConnections.length; a++) {
let toElement = newContainer.HasElement(elementConnections[a].ToElement);
if (toElement) {
if (elementConnections[a].FromContainer) {
let fromElement = elementConnections[a].FromContainer.HasElement(elementConnections[a].fromElement);
let newConnection = new ContainerConnection(elementConnections[a].FromContainer,newContainer,fromElement,toElement,elementConnections[a].Input);
elementConnections[a].Element.Outputs.push(newConnection);
} else {
let newConnection = new ElementConnection(newContainer, toElement, elementConnections[a].Input, elementConnections[a].Output);
//elementConnections[a].FromElement.addConnection(newContainer,toElement,elementConnections[a].Input,elementConnections[a].Output)
if (newConnection) {
//elementConnections[a].FromElement.OutputConnections.push(newConnection);
elementConnections[a].FromElement.addConnection(newContainer,toElement,elementConnections[a].Input, elementConnections[a].Output)
} else {
console.log("We dont have a new connection!!!");
console.log(toElement);
console.log(elementConnections[a]);
}
}
}
}
/*
for (let a = 0; a < icelementConnections.length; a++) {
let fromElement = icelementConnections[a].FromContainer.HasElement(icelementConnections[a].FromElement);
let toElement = newContainer.HasElement(icelementConnections[a].ToElement);
if (toElement) {
icelementConnections[a].Element.addConnection(newContainer, toElement, icelementConnections[a].Input);
}
}
*/
return newContainer;
}
function loadsave(savedata) {
if (!savedata) return 0;
if (!savedata.Version) return -1; // TODO: Let the person know invalid save file
if (!isVersionNewer(savedata.Version,"0.3.0")) return -2; // TODO: Let the person know the version is too old
if (savedata?.Compressed) savedata.Elements = JSON.parse(LZString.decompressFromUTF16(savedata.Elements));
let newContainer = loadContainer(savedata.Elements);
if (!newContainer) return -3;
let saveName = document.getElementById("saveName");
saveName.value = savedata.Name;
logicEngine.ActiveContainer = newContainer;
logicEngine.Panning.OffsetX = 0;
logicEngine.Panning.OffsetY = 0;
logicEngine.Ctx.setTransform(1,0,0,1,0,0);
if (savedata.PanX) {
logicEngine.Panning.OffsetX = savedata.PanX;
logicEngine.Panning.OffsetY = savedata.PanY;
logicEngine.Ctx.translate(logicEngine.Panning.OffsetX,logicEngine.Panning.OffsetY);
}
logicEngine.RedrawStatics();
return true;
}