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 @@
+
+
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();