diff --git a/README.md b/README.md index 487b6a9..8023742 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,12 @@ To be decided, but at this moment this code is open source and free to use for n ## Changelog +### 0.4.6 + +* Added a new keybinding system, and added many keyboard shortcuts (look in menu) +* Fixed a bug where a button would stay on off the mouse was moved away from it while being eld down +* Fixed a bug where you could link from elements with no outouts + ### 0.4.5 * Keypad now supports either Switch, or Button mode for Function keys, also has Clear output that pulses for 100ms when Clr is pressed diff --git a/css/main.css b/css/main.css index e411f0a..b33031f 100644 --- a/css/main.css +++ b/css/main.css @@ -500,10 +500,24 @@ textarea { font-size: 2em; } -#top-menu li span { + +.menuitem-label { +} +.menuitem-label, .menuitem-shortcut { display: inline-block; + margin: 0px; +} +.menuitem-shortcut { padding-left: 10px; float: right; + color: rgba(255,255,255,0.5); +} + +#top-menu li span.checkbox, #top-menu li span.blankbox { + display: inline-block; + padding-right: 10px; + width: 1em; + float: left; } #RightClickMenu ul, .top-menu-div ul { diff --git a/index.html b/index.html index 517c7d2..6233bbb 100644 --- a/index.html +++ b/index.html @@ -32,7 +32,6 @@ -
@@ -40,9 +39,9 @@
  • File
      -
    • New
    • -
    • Open
    • -
    • Save
    • +
    • New
    • +
    • Open
    • +
    • Save
    • Save As
    @@ -50,40 +49,40 @@
  • Edit
      -
    • Undo
    • -
    • Redo
    • +
    • Undo
    • +
    • Redo
    • Cut
    • Copy
    • Paste
    • -
    • Delete
    • -
    • Disconnect
    • +
    • Delete
    • +
    • Disconnect
    • -
    • Select All
    • +
    • Select All
  • View
      -
    • Pan to Center
    • +
    •  Pan to Center
    • -
    • Show Connections
    • -
    • Connections Below
    • +
    • Show Connections
    • +
    •  Connections Below
    • -
    • Show Grid
    • -
    • Snap to Grid
    • -
    • Grid Size
    • +
    • Show Grid
    • +
    • Snap to Grid
    • +
    •  Grid Size Shift+(-,+)
    • -
    • Show FPS
    • +
    • Show FPS
  • Tools
      -
    • Create IC
    • +
    • Create IC
  • diff --git a/js/elements.js b/js/elements.js index e82582b..ee33f08 100644 --- a/js/elements.js +++ b/js/elements.js @@ -463,6 +463,7 @@ class LabelElement extends Element { this.Font = "48px Console"; this.FontStyle = "black"; this.Label = this.Name; + this.NoOutput = true; let LabelProperty = new ElementProperty("Label","string",{CBObject: this,CBFunction: "setLabel"},"Label","Label",false,1,255); this.Properties.push(LabelProperty); let LabelSize = new ElementProperty("Size","int",{CBObject: this,CBFunction: "setSize"},"48","48",false,6,99999); @@ -1395,6 +1396,18 @@ class InputButton extends inputElement { } } + mouseInside(mousePos) { + let mousestat = super.mouseInside(mousePos); + if (this.Output && !this.MouseOver) { + this.Output = false; + for (let a = 0; a < this.OutputConnections.length; a++) { + this.LogicEngine.RecursionCount = 0; + this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input, this.getOutput()); + } + } + return mousestat; + } + drawElement(x, y, ctx) { this.drawBorderBox(ctx, x,y,this.Width-20,this.Height,1,"#000","#f7e979",this.LogicEngine.Settings.ShadowColor); this.drawBorderBox(ctx,x+5,y+5,50,50,1,"#ccc","#777"); diff --git a/js/globalfunctions.js b/js/globalfunctions.js index 9ad59f4..75a1178 100644 --- a/js/globalfunctions.js +++ b/js/globalfunctions.js @@ -113,6 +113,45 @@ function length2D(x1,y1,x2,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 BuildToolbox() { let toolbox = document.getElementById("inner-left-menu"); toolbox.innerHTML = ""; diff --git a/js/logicengine.js b/js/logicengine.js index 5951997..7f714b4 100644 --- a/js/logicengine.js +++ b/js/logicengine.js @@ -16,6 +16,165 @@ class LogicEngineSettings { this.HideConnections = false; this.GridSize = 20; this.ShowFPS = true; + this.Keybindings = { + FileNew: {Key: "n", // lowercase + Alt: false, + Shift: false, + Ctrl: true, + Meta: false, + Name: "New Design", + Description: "Start a new design", + Category: "File"}, + FileOpen: {Key: "o", // lowercase + Alt: false, + Shift: false, + Ctrl: true, + Meta: false, + Name: "Open Design", + Description: "Open a design", + Category: "File"}, + FileSave: {Key: "s", // lowercase + Alt: false, + Shift: false, + Ctrl: true, + Meta: false, + Name: "Save Design", + Description: "Save current design", + Category: "File"}, + EditUndo: {Key: "z", // lowercase + Alt: false, + Shift: false, + Ctrl: true, + Meta: false, + Name: "Undo", + Description: "Steps back through the last things you have done reversing them", + Category: "Edit"}, + EditRedo: {Key: "y", // lowercase + Alt: false, + Shift: false, + Ctrl: true, + Meta: false, + Name: "Redo", + Description: "Reverse any changes done via Redo", + Category: "Edit"}, + DeleteElements: {Key: "delete", + Alt: false, + Shift: false, + Ctrl: false, + Meta: false, + Name: "Delete Element(s)", + Description: "Delete currently selected elements", + Category: "Edit"}, + DisconnectElements: {Key: "d", + Alt: false, + Shift: true, + Ctrl: false, + Meta: false, + Name: "Disconnect Element(s)", + Description: "Disconnect currently selected elements", + Category: "Edit"}, + SelectAll: {Key: "a", // lowercase + Alt: false, + Shift: false, + Ctrl: true, + Meta: false, + Name: "Select All", + Description: "Select all elments in the design", + Category: "Edit"}, + ResetCanvas: {Key: "home", // lowercase + Alt: false, + Shift: false, + Ctrl: false, + Meta: false, + Name: "Reset View", + Description: "Resets the pan back to the default location", + Category: "View"}, + ShowConnections: {Key: "c", // lowercase + Alt: false, + Shift: true, + Ctrl: false, + Meta: false, + Name: "Toggle Connections", + Description: "Show / Hide connections", + Category: "View"}, + ConnectionLayer: {Key: "c", // lowercase + Alt: false, + Shift: true, + Ctrl: true, + Meta: false, + Name: "Connection Layer", + Description: "Toggle connections above / below elements", + Category: "View"}, + ShowGrid: {Key: "g", // lowercase + Alt: false, + Shift: true, + Ctrl: false, + Meta: false, + Name: "Toggle Grid", + Description: "Show / Hide the grid", + Category: "View"}, + SnapGrid: {Key: "g", // lowercase + Alt: true, + Shift: true, + Ctrl: false, + Meta: false, + Name: "Snap to Grid", + Description: "Snap to grid or not", + Category: "View"}, + GridPlus: {Key: "+", // lowercase + Alt: false, + Shift: true, + Ctrl: false, + Meta: false, + Name: "Enlarge Grid", + Description: "Make the grid larger", + Category: "View"}, + GridMinus: {Key: "-", // lowercase + Alt: false, + Shift: true, + Ctrl: false, + Meta: false, + Name: "Shrink Grid", + Description: "Make the grid smaller", + Category: "View"}, + ShowFPS: {Key: "f3", // lowercase + Alt: false, + Shift: false, + Ctrl: false, + Meta: false, + Name: "Toggle FPS", + Description: "Show / Hide FPS counter", + Category: "View"}, + CreateIC: {Key: "c", // lowercase + Alt: false, + Shift: false, + Ctrl: true, + Meta: false, + Name: "Create IC", + Description: "Turns the current design into an IC", + Category: "Tools"}, + Help: {Key: "f1", // lowercase + Alt: false, + Shift: false, + Ctrl: false, + Meta: false, + Name: "Help Window", + Description: "Opens help window", + Category: "Other"} + + + /* + keybind_name: {Key: "", // lowercase + Alt: false, + Shift: false, + Ctrl: false, + Meta: false, + Name: "", + Description: "", + Category: ""} + + */ + }; } } @@ -225,7 +384,76 @@ class LogicEngine { this.MovingElement = false; } } - if (evt.key == "Delete") { + + if (MatchesPress(this.Settings.Keybindings.FileNew,evt)) { + evt.preventDefault(); + tfm_New.click(evt); + } + + if (MatchesPress(this.Settings.Keybindings.FileOpen,evt)) { + evt.preventDefault(); + alert("It is not possible to do a dialog box file open with javascript keyboard shortcuts, however this feature will work soon once server storage is implemented! Until then you will have to click on Open."); + } + + if (MatchesPress(this.Settings.Keybindings.FileSave,evt)) { + evt.preventDefault(); + tfm_Save.click(evt); + } + + if (MatchesPress(this.Settings.Keybindings.ResetCanvas,evt)) { + evt.preventDefault(); + tfm_Pan2Center.click(evt); + } + + if (MatchesPress(this.Settings.Keybindings.ShowConnections,evt)) { + evt.preventDefault(); + tfm_ShowConns.click(evt); + } + + if (MatchesPress(this.Settings.Keybindings.ConnectionLayer,evt)) { + evt.preventDefault(); + tfm_ConnLayer.click(evt); + } + + if (MatchesPress(this.Settings.Keybindings.SelectAll,evt)) { + evt.preventDefault(); + tfm_SelectAll.click(evt); + } + + if (MatchesPress(this.Settings.Keybindings.ShowGrid,evt)) { + evt.preventDefault(); + tfm_ShowGrid.click(evt); + } + + if (MatchesPress(this.Settings.Keybindings.SnapGrid,evt)) { + evt.preventDefault(); + tfm_SnapGrid.click(evt); + } + + if (MatchesPress(this.Settings.Keybindings.GridPlus,evt)) { + evt.preventDefault(); + in_GridSize.value = logicEngine.Settings.GridSize + Math.ceil(logicEngine.Settings.GridSize * 0.05); + in_GridSize.dispatchEvent(new Event('change')); + } + + if (MatchesPress(this.Settings.Keybindings.GridMinus,evt)) { + evt.preventDefault(); + in_GridSize.value = ((logicEngine.Settings.GridSize - Math.ceil(logicEngine.Settings.GridSize * 0.05)) < 2) ? 2 : logicEngine.Settings.GridSize - Math.ceil(logicEngine.Settings.GridSize * 0.05) ; + in_GridSize.dispatchEvent(new Event('change')); + } + + if (MatchesPress(this.Settings.Keybindings.ShowFPS,evt)) { + evt.preventDefault(); + tfm_ShowFPS.click(evt); + } + + if (MatchesPress(this.Settings.Keybindings.CreateIC,evt)) { + evt.preventDefault(); + tfm_CreateIC.click(evt); + } + + + if (MatchesPress(this.Settings.Keybindings.DeleteElements,evt)) { if (this.ActiveContainer.Selected?.length > 0) { this.ActiveContainer.DeleteElement(this.ActiveContainer.Selected); this.ActiveContainer.Selected = false; @@ -233,6 +461,15 @@ class LogicEngine { PropertiesBox.style.display = "none"; } } + + if (MatchesPress(this.Settings.Keybindings.DisconnectElements,evt)) { + if (this.ActiveContainer.Selected?.length > 0) { + for (let a = 0; a < logicEngine.ActiveContainer.Selected.length; a++) { + logicEngine.ActiveContainer.Selected[a].Disconnect(); + } + logicEngine.ActiveContainer.Disconnect(logicEngine.ActiveContainer.Selected); + } + } } constructor(canvas) { @@ -279,7 +516,8 @@ class LogicEngine { } } else { if (this.ActiveContainer.Selected.length == 1) { - this.ActiveLink = this.ActiveContainer.Selected[0]; + + if (!this.ActiveContainer.Selected[0].NoOutput) this.ActiveLink = this.ActiveContainer.Selected[0]; } } diff --git a/js/main.js b/js/main.js index 9e00299..96f6540 100644 --- a/js/main.js +++ b/js/main.js @@ -2,7 +2,7 @@ MatCat BrowserLogic Simulator */ -let Version = "0.4.5"; +let Version = "0.4.6"; let spanVersion = document.getElementById("version"); spanVersion.innerText = Version; // get the canvas and get the engine object going @@ -160,6 +160,16 @@ tfm_Disconect.addEventListener('click', function(evt) { setTimeout(function(){hideMenus()},10); }); +let tfm_SelectAll = document.getElementById("tfm_SelectAll"); +tfm_SelectAll.addEventListener('click', function(evt) { + let elements = new Array(); + for (let a = 0; a < logicEngine.ActiveContainer.Elements?.length;a++) { + elements.push(logicEngine.ActiveContainer.Elements[a]); + } + logicEngine.ActiveContainer.Selected = elements; + setTimeout(function(){hideMenus()},10); +}); + let tfm_Save = document.getElementById("tfm_Save"); tfm_Save.addEventListener('click', function(evt) { @@ -222,6 +232,9 @@ file_Load.addEventListener('change', function(evt) { fread.readAsText(evt.target.files[0]); }, false); +/* + Generate the top menu item listeners + */ let tfms = document.getElementsByClassName("top-menu-item"); for (let a = 0; a < tfms.length; a++) { tfms[a].addEventListener("click", function (evt) { @@ -231,6 +244,14 @@ for (let a = 0; a < tfms.length; a++) { tfm.style.top = (tfm_rect.top + tfm_rect.height) + "px"; tfm.style.display = "block"; }); + let tfm = document.getElementById(tfms[a].id + "Menu"); + if (!tfm.classList.contains("keybinding-complete")) { + tfm.classList.add("keybinding-complete"); + let menuItems = tfm?.getElementsByTagName("li"); + for (let b = 0; b < menuItems?.length; b++) { + if (menuItems[b]?.getAttribute("value")) menuItems[b].innerHTML = '' + menuItems[b].innerHTML + '' + (KeybindToString(logicEngine.Settings.Keybindings[menuItems[b].getAttribute("value")])) + ''; + } + } } let tfm_About = document.getElementById("tfm_About"); @@ -243,12 +264,12 @@ tfm_About.addEventListener("click", function (evt) { let tfm_ShowConns = document.getElementById("tfm_ShowConnections"); tfm_ShowConns.addEventListener("click", function (evt) { if (logicEngine.Settings.HideConnections) { - let sgSpan = tfm_ShowConns.getElementsByTagName("span")[0]; + let sgSpan = tfm_ShowConns.getElementsByClassName("checkbox")[0]; sgSpan.innerText = "✓"; logicEngine.Settings.HideConnections = false; } else { - let sgSpan = tfm_ShowConns.getElementsByTagName("span")[0]; - sgSpan.innerText = ""; + let sgSpan = tfm_ShowConns.getElementsByClassName("checkbox")[0]; + sgSpan.innerHTML = " "; logicEngine.Settings.HideConnections = true; } setTimeout(function(){hideMenus()},10); @@ -269,11 +290,11 @@ tfm_ConnLayer.addEventListener("click", function (evt) { let tfm_ShowFPS = document.getElementById("tfm_ShowFPS"); tfm_ShowFPS.addEventListener("click", function (evt) { if (logicEngine.Settings.ShowFPS) { - let sgSpan = tfm_ShowFPS.getElementsByTagName("span")[0]; - sgSpan.innerText = ""; + let sgSpan = tfm_ShowFPS.getElementsByClassName("checkbox")[0]; + sgSpan.innerHTML = " "; logicEngine.Settings.ShowFPS = false; } else { - let sgSpan = tfm_ShowFPS.getElementsByTagName("span")[0]; + let sgSpan = tfm_ShowFPS.getElementsByClassName("checkbox")[0]; sgSpan.innerText = "✓"; logicEngine.Settings.ShowFPS = true; } @@ -293,11 +314,11 @@ tfm_Pan2Center.addEventListener("click", function (evt) { let tfm_ShowGrid = document.getElementById("tfm_ShowGrid"); tfm_ShowGrid.addEventListener("click", function (evt) { if (logicEngine.Settings.ShowGrid) { - let sgSpan = tfm_ShowGrid.getElementsByTagName("span")[0]; - sgSpan.innerText = ""; + let sgSpan = tfm_ShowGrid.getElementsByClassName("checkbox")[0]; + sgSpan.innerHTML = " "; logicEngine.Settings.ShowGrid = false; } else { - let sgSpan = tfm_ShowGrid.getElementsByTagName("span")[0]; + let sgSpan = tfm_ShowGrid.getElementsByClassName("checkbox")[0]; sgSpan.innerText = "✓"; logicEngine.Settings.ShowGrid = true; } @@ -308,11 +329,11 @@ tfm_ShowGrid.addEventListener("click", function (evt) { let tfm_SnapGrid = document.getElementById("tfm_SnapGrid"); tfm_SnapGrid.addEventListener("click", function (evt) { if (logicEngine.Settings.SnapGrid) { - let sgSpan = tfm_SnapGrid.getElementsByTagName("span")[0]; - sgSpan.innerText = ""; + let sgSpan = tfm_SnapGrid.getElementsByClassName("checkbox")[0]; + sgSpan.innerHTML = " "; logicEngine.Settings.SnapGrid = false; } else { - let sgSpan = tfm_SnapGrid.getElementsByTagName("span")[0]; + let sgSpan = tfm_SnapGrid.getElementsByClassName("checkbox")[0]; sgSpan.innerText = "✓"; logicEngine.Settings.SnapGrid = true; }