diff --git a/README.md b/README.md index 387cd3e..2002c4c 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,13 @@ To be decided, but at this moment this code is open source and free to use for n ## Changelog +### 0.4.0 + +* You can now pan the work area, hold ctrl key while mouse dragging an empty area. +* Right Click Menu + * If an item is selected you can delete or disconnect them (BUG WIP: Doesn't disconnect IC's) +* Save dialog + ### 0.3.10 * Added BCD and Decimal options to the 4 bit output display, as well as bit labels in inputs diff --git a/css/main.css b/css/main.css index a752759..ce78f70 100644 --- a/css/main.css +++ b/css/main.css @@ -366,7 +366,7 @@ textarea { #WelcomeWindow label { font-size: 0.5em; } -#PropertiesBox, #CreateICBox { +#PropertiesBox, #CreateICBox, #SaveWindow { display: none; position: absolute; right: 20px; @@ -387,16 +387,70 @@ textarea { border: 3px solid red; } -#PropertiesBoxTitle, #CreateICBoxTitle { +#SaveWindow { + width: 350px; + height: 120px; +} + +#SaveWindowContent { + margin: auto; + width: 90%; + margin-top: 10px; +} + +#PropertiesBoxTitle, #CreateICBoxTitle, #SaveWindowTitle { text-align: center; background-color: #222222; font-size: 1.5em; } -#PropertiesBoxContent, #CreateICBoxContent { +#PropertiesBoxContent, #CreateICBoxContent, #SaveWindowContent { padding: 5px; } +#RightClickMenu { + display: none; + position: absolute; + left: 0px; + top: 0px; + background-color: #444455; + border: 1px solid #232323; + z-index: 9999999999; +} + +#RightClickMenu ul { + margin: 0px; + padding: 0px; +} + +#RightClickMenu li { + cursor: default; + text-decoration: none; + list-style-type: none; + margin: 0px; + padding: 2px; + padding-left: 30px; + padding-right: 30px; +} + +#RightClickMenu li:hover { + background-color: #222222; +} + +#RightClickMenu .disabled { + color: #777777; +} + +.rcm_seperator:hover { + background-color: transparent !important; +} + +.rcm_seperator { + height: 2px; + margin-bottom: 7px; + border-bottom: 2px groove #54545d; +} + #LogicPlane { outline: none; -webkit-tap-highlight-color: rgba(255, 255, 255, 0); /* mobile webkit */ diff --git a/index.html b/index.html index d522f61..e3652da 100644 --- a/index.html +++ b/index.html @@ -68,6 +68,29 @@
   
+
+ +
+
+
+ Save Design +
+
+
+ Design Name +
+
+
   
+
+
+
diff --git a/js/baseclasses.js b/js/baseclasses.js index f6fe603..f3eea9e 100644 --- a/js/baseclasses.js +++ b/js/baseclasses.js @@ -131,6 +131,13 @@ class elementContainer { return false; } + Disconnect(element) { + if (!element) return false; + for (let a = 0; a < this.Elements.length; a++) { + this.Elements[a].Disconnect(element); + } + } + DrawAll(ctx,settings) { let ICOuts = 0; for (let a = 0; a < this.Elements.length; a++) { diff --git a/js/elements.js b/js/elements.js index 37d3dca..74c83f2 100644 --- a/js/elements.js +++ b/js/elements.js @@ -168,9 +168,26 @@ class Element extends CanvasTools { // if we are active linking stop doing so if (this.LogicEngine.ActiveLink == this) this.LogicEngine.ActiveLink = false; // Just to clean up connections - for (let a = 0; a < this.OutputConnections.length;a++) { - this.LogicEngine.RecursionCount = 0; - this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input,false); + this.Disconnect(); + } + + Disconnect(element = false) { + if (element) { + for (let a = 0; a < this.OutputConnections.length; a++) { + if (this.OutputConnections[a].Element == element) { + this.LogicEngine.RecursionCount = 0; + this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input, false); + this.OutputConnections.splice(a,1); + a--; + } + } + } else { + for (let a = 0; a < this.OutputConnections.length; a++) { + this.LogicEngine.RecursionCount = 0; + this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input, false); + this.OutputConnections.splice(a,1); + a--; + } } } @@ -188,10 +205,11 @@ class Element extends CanvasTools { MouseClick(mousePos) { + let ctxMousePos = this.MousePosition; let mouseDistOutput = length2D(this.X+(this.Width-10), this.Y+(this.Height/2), - this.MousePosition.x, - this.MousePosition.y); + ctxMousePos.x, + ctxMousePos.y); if (this.LogicEngine.ActiveLink) { // We need to see if an input is being clicked on to be linked to let foundInput = false; @@ -202,8 +220,8 @@ class Element extends CanvasTools { let mouseDist = length2D(this.X+10, firstY+ (a*24), - this.MousePosition.x, - this.MousePosition.y); + ctxMousePos.x, + ctxMousePos.y); if (mouseDist <= (this.inputCircleRadius)) { this.LogicEngine.Link(a); foundInput = true; @@ -220,8 +238,8 @@ class Element extends CanvasTools { let mouseDist = length2D(this.X+(this.Width-10), firstY+ (a*24), - this.MousePosition.x, - this.MousePosition.y); + ctxMousePos.x, + ctxMousePos.y); console.log("Distance from " + a + ": " + mouseDist); if (mouseDist <= (this.outputCircleRadius)) { this.OutputLink = {Output: a,x: this.X+(this.Width-10), y: firstY+ (a*24)}; @@ -234,8 +252,9 @@ class Element extends CanvasTools { } mouseInside(mousePos) { + mousePos = this.LogicEngine.getCanvasMousePos(mousePos); this.MouseOver = false; - if (((mousePos.x >= this.X ) && (mousePos.x <= (this.X + this.Width))) & ((mousePos.y >= this.Y ) && (mousePos.y <= (this.Y + this.Height)))) this.MouseOver = true; + if (((mousePos.x >= this.X ) && (mousePos.x <= (this.X + this.Width))) && ((mousePos.y >= this.Y ) && (mousePos.y <= (this.Y + this.Height)))) this.MouseOver = true; this.MousePosition = mousePos; return this.MouseOver; } @@ -1142,7 +1161,8 @@ class output4bitDisplay extends Element { this.Properties.push(typeProperty); if (RestoreData) { - if (RestoreData.Properties) { + if (RestoreData.Properties.length > 0) { + console.log(RestoreData); this.Properties[0].CurrentValue = RestoreData.Properties[0].CurrentValue; this.Properties[0].Values = RestoreData.Properties[0].Values; this.setType(this.Properties[0].CurrentValue); @@ -1248,6 +1268,7 @@ class InputSwitch extends inputElement { } MouseClick(mousePos) { + mousePos = this.LogicEngine.getCanvasMousePos(mousePos); super.MouseClick(mousePos); if ((mousePos.x >= (this.X + 5)) && (mousePos.x <= (this.X + 55)) && (mousePos.y >= (this.Y + 5)) && (mousePos.y <= (this.Y + 55))) { this.Output = !this.Output; @@ -1285,6 +1306,7 @@ class InputButton extends inputElement { } MouseDown(mousePos) { + mousePos = this.LogicEngine.getCanvasMousePos(mousePos); if ((mousePos.x >= (this.X + 5)) && (mousePos.x <= (this.X + 55)) && (mousePos.y >= (this.Y + 5)) && (mousePos.y <= (this.Y + 55))) { let old_output = this.Output; this.Output = true; diff --git a/js/globalfunctions.js b/js/globalfunctions.js index e5e4787..25be5ea 100644 --- a/js/globalfunctions.js +++ b/js/globalfunctions.js @@ -2,8 +2,10 @@ function addElement(RestoreData = null,refClass,props) { let newElement = new refClass(RestoreData,logicEngine,...props); if (!RestoreData) { - let x = Math.round(logicEngine.Canvas.width / 2); - let y = Math.round(logicEngine.Canvas.height / 2); + 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; @@ -168,6 +170,19 @@ function isVersionNewer(version1,version2,orEqual = true) { return false; } +function disableSelectedRCMs(bool) { + let rcm_Delete = document.getElementById("rcm_Delete"); + let rcm_Disconnect = document.getElementById("rcm_Disconnect"); + + if (bool) { + rcm_Delete.classList.add("disabled"); + rcm_Disconnect.classList.add("disabled"); + } else { + rcm_Delete.classList.remove("disabled"); + rcm_Disconnect.classList.remove("disabled"); + } +} + function createSaveState(container = false) { let saveState = { Name: "LogicDesign", @@ -203,7 +218,7 @@ function loadContainer(Elements) { 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); + //console.log("NewIC:" + newIC); if (!newIC) return false; } } @@ -241,10 +256,6 @@ function loadContainer(Elements) { } // Now we need to make all of the connections for (let a = 0; a < elementConnections.length; a++) { - if (elementConnections[a].FromElement.Name == "1B_ADD") { - console.log("Making connection " + a); - console.log(elementConnections[a]); - } let toElement = newContainer.HasElement(elementConnections[a].ToElement); if (toElement) { if (elementConnections[a].FromContainer) { @@ -258,12 +269,6 @@ function loadContainer(Elements) { if (newConnection) { //elementConnections[a].FromElement.OutputConnections.push(newConnection); elementConnections[a].FromElement.addConnection(newContainer,toElement,elementConnections[a].Input, elementConnections[a].Output) - if (elementConnections[a].FromElement.Name == "1B_ADD") { - console.log("Making Connection"); - console.log(newConnection); - console.log(elementConnections[a].FromElement); - console.log(elementConnections[a].FromElement.OutputConnections); - } } else { console.log("We dont have a new connection!!!"); console.log(toElement); @@ -291,6 +296,8 @@ function loadsave(savedata) { if (!isVersionNewer(savedata.Version,"0.3.0")) return -2; // TODO: Let the person know the version is too old let newContainer = loadContainer(savedata.Elements); if (!newContainer) return -3; + let saveName = document.getElementById("saveName"); + saveName.value = savedata.Name; logicEngine.ActiveContainer = newContainer; return true; } diff --git a/js/logicengine.js b/js/logicengine.js index a234605..a3dfdef 100644 --- a/js/logicengine.js +++ b/js/logicengine.js @@ -67,7 +67,19 @@ class LogicEngine { this.MovingElementMouseStartY = mousePos.y; element.MouseDown(mousePos); } else { + this.MouseDown = true; this.ActiveLink = false; + if (this.ControlPressed) { + this.Panning.StartOffsetX = this.Panning.OffsetX; + this.Panning.StartOffsetY = this.Panning.OffsetY; + this.Panning.StartX = mousePos.x; + this.Panning.StartY = mousePos.y; + } + } + if (this.ActiveContainer.Selected) { + disableSelectedRCMs(false); + } else { + disableSelectedRCMs(true); } } @@ -82,8 +94,14 @@ class LogicEngine { //console.log("Mouse Up"); } if (!this.MovingElement) this.ActiveContainer.Selected = false; + this.MovingElement = false; this.MouseDown = false; + if (this.ActiveContainer.Selected) { + disableSelectedRCMs(false); + } else { + disableSelectedRCMs(true); + } } Mouse_Move(evt) { @@ -105,6 +123,18 @@ class LogicEngine { this.MovingElement.X = actualPosX; this.MovingElement.Y = actualPosY; } + } else { + if (this.ControlPressed) { + let distX = mousePos.x - this.Panning.StartX; + let distY = mousePos.y - this.Panning.StartY; + this.Panning.StartX += distX; + this.Panning.StartY += distY; + + this.Panning.OffsetX += distX; + this.Panning.OffsetY += distY; + + this.Ctx.translate(distX, distY); + } } } else { this.ActiveContainer.checkMouseBounds(mousePos); @@ -164,6 +194,7 @@ class LogicEngine { this.RecursionError = false; this.Canvas.setAttribute('tabindex','0'); this.ControlPressed = false; + this.Panning = {OffsetX: 0, OffsetY: 0,StartOffsetX: 0, StartOffsetY: 0, StartX: 0, StartY: 0}; } @@ -183,23 +214,31 @@ class LogicEngine { } + getCanvasMousePos(mousePos) { + return {x: mousePos.x - this.Panning.OffsetX, y: mousePos.y - this.Panning.OffsetY}; + } + DrawLoop() { if (this.RecursionError) { this.RecursionError = false; alert("Recursion Error! Whatever you last did is causing an oscillating loop, please check your connections and try again!"); } let startLoop = performance.now(); - this.Ctx.clearRect(0,0,this.Canvas.width,this.Canvas.height); + this.Ctx.clearRect(0- this.Panning.OffsetX,0- this.Panning.OffsetY,this.Canvas.width,this.Canvas.height); this.ActiveContainer.DrawAll(this.Ctx,this.Settings); let btn_CreateIC = document.getElementById("btn_CreateIC"); + let rcm_CreateIC = document.getElementById("rcm_CreateIC"); + btn_CreateIC.disabled = true; + rcm_CreateIC.classList.add("disabled"); if (this.ActiveContainer.ICOutputs > 0) btn_CreateIC.disabled = false; + if (this.ActiveContainer.ICOutputs > 0) rcm_CreateIC.classList.remove("disabled"); if (this.ActiveLink) { let startX = this.ActiveLink.LinkOutLocation().x; let startY = this.ActiveLink.LinkOutLocation().y; - let endX = this.Mouse.x; - let endY = this.Mouse.y; + let endX = this.Mouse.x - this.Panning.OffsetX; + let endY = this.Mouse.y - this.Panning.OffsetY; let startMidX = startX + ((endX - startX)/2); let startMidY = startY; let midX = startMidX; @@ -207,6 +246,7 @@ class LogicEngine { let endMidX = startMidX; let endMidY = endY; + this.Ctx.save(); this.Ctx.strokeStyle = this.Settings.LinkingConnectionColor; this.Ctx.lineWidth = this.Settings.LinkingWidth; @@ -219,9 +259,9 @@ class LogicEngine { this.Ctx.restore(); } let ct = new CanvasTools(); - let FPSOffset = this.Canvas.width - 150; - ct.drawText(this.Ctx,FPSOffset,650,"FPS: " + this.FPS,"12px console", "#00ff00"); - ct.drawText(this.Ctx,FPSOffset,670,"Potential FPS: " + this.PotentialFPS,"12px console", "#00ff00"); + let FPSOffset = (this.Canvas.width - 150) - this.Panning.OffsetX; + ct.drawText(this.Ctx,FPSOffset,650- this.Panning.OffsetY,"FPS: " + this.FPS,"12px console", "#00ff00"); + ct.drawText(this.Ctx,FPSOffset,670- this.Panning.OffsetY,"Potential FPS: " + this.PotentialFPS,"12px console", "#00ff00"); let timeCheck = performance.now(); this.FPSCounter++; diff --git a/js/main.js b/js/main.js index b540ac6..2986ae8 100644 --- a/js/main.js +++ b/js/main.js @@ -2,7 +2,7 @@ MatCat BrowserLogic Simulator */ -let Version = "0.3.10"; +let Version = "0.4.0"; let spanVersion = document.getElementById("version"); spanVersion.innerText = Version; // get the canvas and get the engine object going @@ -25,6 +25,11 @@ window.addEventListener('keyup', function(evt) { logicEngine.Key_Up(evt); }, false); +window.addEventListener('mouseup', function(evt) { + let rcm = document.getElementById("RightClickMenu"); + rcm.style.display = "none"; +}, false); + lCanvasElement.addEventListener('mousedown', function(evt) { logicEngine.Mouse_Down(evt); @@ -61,6 +66,14 @@ btn_CreateIC.addEventListener('click', function(evt) { CreateICBox.style.display = "block"; }); +let rcm_CreateIC = document.getElementById("rcm_CreateIC"); +rcm_CreateIC.addEventListener('click', function(evt) { + if (!this.classList.contains("disabled")) { + let CreateICBox = document.getElementById("CreateICBox"); + CreateICBox.style.display = "block"; + } +}); + let btn_CreateIC_Cancel = document.getElementById("btn_CreateIC_Cancel"); btn_CreateIC_Cancel.addEventListener('click', function(evt) { let CreateICBox = document.getElementById("CreateICBox"); @@ -94,10 +107,46 @@ btn_New.addEventListener('click', function(evt) { logicEngine.ActiveContainer = new elementContainer(); }); +let rcm_New = document.getElementById("rcm_New"); +rcm_New.addEventListener('click', function(evt) { + logicEngine.ActiveContainer = new elementContainer(); +}); + +let rcm_Delete = document.getElementById("rcm_Delete"); +rcm_Delete.addEventListener('click', function(evt) { + logicEngine.Key_Press({ctrlKey: false, key: "Delete"}); +}); + +let rcm_Disconect = document.getElementById("rcm_Disconnect"); +rcm_Disconect.addEventListener('click', function(evt) { + logicEngine.ActiveContainer.Selected.Disconnect(); + logicEngine.ActiveContainer.Disconnect(logicEngine.ActiveContainer.Selected); +}); + let btn_Save = document.getElementById("btn_Save"); btn_Save.addEventListener('click', function(evt) { - download("mydeign.LogicParts",createSaveState(logicEngine.ActiveContainer)); + //download("mydeign.LogicParts",createSaveState(logicEngine.ActiveContainer)); + let saveWindow = document.getElementById("SaveWindow"); + saveWindow.style.display="block"; + saveWindow.style.left = Math.round((window.innerWidth / 2) - (saveWindow.clientWidth/2)) + "px"; + saveWindow.style.top = Math.round((window.innerHeight / 2) - (saveWindow.clientHeight/2)) + "px"; +}); + +let btn_SaveDesign = document.getElementById("btn_SaveDesign"); +btn_SaveDesign.addEventListener('click', function(evt) { + let DesignName = document.getElementById("saveName"); + let savestate = createSaveState(logicEngine.ActiveContainer); + savestate.Name = DesignName.value; + let saveWindow = document.getElementById("SaveWindow"); + saveWindow.style.display = "none"; + download(savestate.Name + ".LogicParts",savestate); +}); + +let btn_Save_Cancel = document.getElementById("btn_CancelSave"); +btn_Save_Cancel.addEventListener('click', function(evt) { + let saveWindow = document.getElementById("SaveWindow"); + saveWindow.style.display = "none"; }); let file_Load = document.getElementById("file_Load"); @@ -127,7 +176,7 @@ file_Load.addEventListener('change', function(evt) { } } } catch (ex) { - alert("Bad file!"); + alert("Bad file! " + ex); console.log(ex); } } @@ -135,5 +184,15 @@ file_Load.addEventListener('change', function(evt) { fread.readAsText(evt.target.files[0]); }, false); +document.addEventListener( "contextmenu", function(evt) { + evt.preventDefault(); + let rcm = document.getElementById("RightClickMenu"); + rcm.style.left = (evt.clientX-40) + "px"; + rcm.style.top = (evt.clientY-25) + "px"; + console.log(rcm.style); + rcm.style.display = "block"; + console.log(evt); + +}); CheckForWelcomeCookie();