class ICInput extends Element { setPinName(pinname) { // Dont actually need it to do anything this.Properties[0].CurrentValue = pinname; this.Output = false; this.drawElement(0,0,this.StaticCtx); } constructor(_Container, RestoreData = null,logicengine) { super(_Container, RestoreData ,logicengine,0); this.removeProperty("Inputs"); this.Task = new Task("ICInputTask","CLOCK",0,1,this.ClockTick.bind(this)); this.Name = "ICInput"; this.Input = false; let pinNameProperty = new ElementProperty("Pin Name","string",{CBObject: this,CBFunction: "setPinName"},"Pin","Pin",false,1,32); this.Properties.push(pinNameProperty); this.LogicEngine.Scheduler.addTask(this.Task); if (RestoreData) { pinNameProperty.CurrentValue = RestoreData.Properties[0].CurrentValue; } } toJSON(key) { let superjson = super.toJSON(key); superjson.Task = { Enabled: this.Task.Enabled, Time: this.Task.Time, LastCall: Date.now() - this.Task.LastCall, CallCount: this.Task.CallCount }; return superjson; } setInput(notused = 0,value) { if (notused > 0) return; if (value === false) this.Input = false; if (value !== false) this.Input = true; this.Inputs[0] = this.Input; this.drawElement(0,0,this.StaticCtx); if (!this.Task.Enabled) { this.Task.LastCall = 0; this.Task.Enabled = true; } } ClockTick() { this.Output = this.Input; this.Task.Enabled = false; this.Task.LastCall = 0; this.drawElement(0,0,this.StaticCtx); for (let a = 0; a < this.OutputConnections.length; a++) { this.LogicEngine.RecursionCount = 0; this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input, this.getOutput()); } } Delete() { super.Delete(); this.LogicEngine.Scheduler.deleteTask(this.Task); } getOutput(Output=0) { if (super.getOutput() === 0) return false; return this.Output; } drawElement(x,y,ctx) { if (this.LogicEngine.ActiveContainer !== this._Container) return; // No point if we aren't visible /* Draw routine for the element */ this.StaticCanvas.width = this.Width; 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.drawTextCentered(ctx,x,y+2,this.Width-10,14,this.Designator,"12px Console"); this.drawTextCentered(ctx,x,y,this.Width-10,this.Height,label,"12px Console",undefined,drawOverline); this.drawOutputs(ctx,x,y); } } let ElementCatalog_ICInput = new ElementCatalog_Element("ICInput","Allows for external signal to be applied to the design when used as an IC.","-<|",ICInput,[]); ElementReferenceTable.push(ElementCatalog_ICInput); ElementCategory_ICs.addElement(ElementCatalog_ICInput); class ICOutput extends Element { setPinName(pinname) { // Dont actually need it to do anything this.Properties[0].CurrentValue = pinname; this.Output = false; this.drawElement(0,0,this.StaticCtx); } constructor(_Container, RestoreData = null,logicengine) { super(_Container, RestoreData ,logicengine,1); this.removeProperty("Inputs"); this.Task = new Task("ICOutputTask","CLOCK",0,1,this.ClockTick.bind(this)); this.Name = "ICOutput"; this.Input = false; this.NoOutput = true; this.ParentIC = false; let pinNameProperty = new ElementProperty("Pin Name","string",{CBObject: this,CBFunction: "setPinName"},"Pin","Pin",false,1,32); this.Properties.push(pinNameProperty); this.LogicEngine.Scheduler.addTask(this.Task); if (RestoreData) { pinNameProperty.CurrentValue = RestoreData.Properties[0].CurrentValue; } } setParent(element) { this.ParentIC = element; } toJSON(key) { let superjson = super.toJSON(key); superjson.Task = { Enabled: this.Task.Enabled, Time: this.Task.Time, LastCall: Date.now() - this.Task.LastCall, CallCount: this.Task.CallCount }; return superjson; } setInput(notused = 0,value) { if (notused > 0) return; value = this._Container.isHigh(this,0); if (value === false) this.Input = false; if (value !== false) this.Input = true; this.Inputs[0] = this.Input; this.drawElement(0,0,this.StaticCtx); if (!this.Task.Enabled) { this.Task.LastCall = 0; this.Task.Enabled = true; } } ClockTick() { this.Output = this.Input; this.Task.Enabled = false; this.Task.LastCall = 0; this.drawElement(0,0,this.StaticCtx); for (let a = 0; a < this.OutputConnections.length; a++) { this.LogicEngine.RecursionCount = 0; this.OutputConnections[a].Element.setInput(this.OutputConnections[a].Input, this.getOutput()); } if (this.ParentIC) { this.ParentIC.drawOutputs(this.ParentIC.StaticCtx,0,0); } } Delete() { super.Delete(); this.LogicEngine.Scheduler.deleteTask(this.Task); } getOutput(Output=0) { if (super.getOutput() === 0) return false; return this.Output; } drawConnections(ctx, settings) { // Don't draw connections from IC Outputs } drawOutputs(ctx, x, y, borderColor = "#000", circleColorFalse = "#ff0000", circleColorTrue = "#00ff00", circleColorHover = "#00ffff") { // Don't draw outputs } drawElement(x,y,ctx) { if (this.LogicEngine.ActiveContainer !== this._Container) return; // No point if we aren't visible /* Draw routine for the element */ this.StaticCanvas.width = this.Width; 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.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,label,"12px Console",undefined,drawOverline); this.drawInputs(ctx,x,y,undefined,undefined,undefined,undefined,true); } } let ElementCatalog_ICOutput = new ElementCatalog_Element("ICOutput","Allows for routing a signal externally when the design is used as an IC.","|>-",ICOutput,[]); ElementReferenceTable.push(ElementCatalog_ICOutput); ElementCategory_ICs.addElement(ElementCatalog_ICOutput); class ICElement extends Element { constructor(_Container, RestoreData = null, logicengine,ICSettings = null) { let newContainer = false; let icContainer = false; try { newContainer = loadContainer(JSON.parse(JSON.parse(ICSettings.Container))); icContainer = loadContainer(JSON.parse(JSON.parse(ICSettings.Container))); } catch (ex) { newContainer = loadContainer(JSON.parse(ICSettings.Container)); icContainer = loadContainer(JSON.parse(ICSettings.Container)); } ICSettings.Inputs = new Array(); ICSettings.Outputs = new Array(); let inputLabels = new Array(); let outputLabels = new Array(); for (let a = 0; a < newContainer.Elements.length; a++) { if (newContainer.Elements[a] instanceof ICInput) { let cConn = new ContainerConnection(null,newContainer,null,newContainer.Elements[a],0); inputLabels.push(newContainer.Elements[a]?.Properties[0]?.CurrentValue); ICSettings.Inputs.push(cConn); } if (newContainer.Elements[a] instanceof ICOutput) { let cConn = new ContainerConnection(newContainer,null,newContainer.Elements[a],null,0); outputLabels.push(newContainer.Elements[a]?.Properties[0]?.CurrentValue); ICSettings.Outputs.push(cConn); } } let totalInputs = ICSettings.Inputs.length; let totalOutputs = ICSettings.Outputs.length; super(_Container, RestoreData, logicengine, totalInputs); this.removeProperty("Inputs"); this.ICBlueprint = icContainer; this.Outputs = ICSettings.Outputs; this.InputConnections = ICSettings.Inputs; this.InputLabels = inputLabels; this.OutputLabels = outputLabels; this.Container = newContainer; this.Name = ICSettings.Name; this.Icon = "≡[°]≡"; this.Width = 140; this.Height = (totalInputs >= totalOutputs) ? totalInputs*25 : totalOutputs*25; if (this.Height < 60) this.Height = 60; for (let a = 0; a < this.Outputs.length; a++) { this.Outputs[a].fromElement.setParent(this); } let editProperty = new ElementProperty("Edit","button",{CBObject: this,CBFunction: "editIC"},"Edit IC","Edit IC",false,0,0); this.Properties.push(editProperty); if (RestoreData) { //console.log(RestoreData); } } toJSON(key) { let superjson = super.toJSON(key); superjson.IsIC = true; let eCat = getElementInfo(this.Name); superjson.Description = eCat.Description; superjson.ICOutputs = this.Outputs; superjson.InputConnections = this.InputConnections; superjson.ICBlueprint = this.ICBlueprint; superjson.ICContainer = this.Container; return superjson; } editIC(value) { if (this.LogicEngine.StashedContainer) { this.LogicEngine.StashedContainer.push(this.LogicEngine.ActiveContainer); } else { this.LogicEngine.StashedContainer = new Array(); this.LogicEngine.StashedContainer.push(this.LogicEngine.ActiveContainer); } this.LogicEngine.ActiveContainer = this.ICBlueprint; this.LogicEngine.RedrawStatics(); } Disconnect(element = false) { super.Disconnect(element); if (element) { for (let a = 0; a < this.Outputs.length; a++) { if (this.Outputs[a].toElement == element || this.Outputs[a].fromElement == element) { if (this.Outputs[a].toElement == element) { // It's a too element, we need to tell it we are not high anymore } else { // Its a from element, we need to tell it's too element } } } } else { // We are disconnecting all of our own connections for (let a = 0; a < this.Outputs.length; a++) { } } } addConnection(container, element, input, output = 0) { super.addConnection(container, element, input, output); this.Outputs[output].toElementContainer = container; this.Outputs[output].toElement = element; this.Outputs[output].Input = input; this.Outputs[output].fromElement.addConnection(container,element,input,0); } setInput(Input, Value) { if (this.InputConnections.length >= Input) { // No need to worry about recursion as this goes to an input element which is buffered Value = this._Container.isHigh(this,Input); this.Inputs[Input] = (Value === false) ? false : true; this.drawElement(0,0,this.StaticCtx); this.InputConnections[Input].toElement.setInput(0,Value); } return false; } getOutput(Output = 0) { if (super.getOutput() === 0) return false; if (this.Outputs.length >= Output) { return this?.Outputs[Output]?.fromElement?.getOutput(this?.Outputs[Output]?.Input); } return false; } drawElement(x,y,ctx) { if (this.LogicEngine.ActiveContainer !== this._Container) return; // No point if we aren't visible /* Draw routine for the element */ this.StaticCanvas.width = this.Width; this.StaticCanvas.height = this.Height; this.clearStatic(); this.drawBorderBox(ctx,x+20,y,this.Width-40,this.Height); this.drawTextCentered(ctx,x,y,this.Width,this.Height,this.Icon,"12px Console"); this.drawTextCentered(ctx,x,(y+this.Height)-14,this.Width,14,this.Designator,"10px Console","#000"); this.drawInputs(ctx,x,y,undefined,undefined,undefined,undefined,true); this.drawOutputs(ctx,x,y,undefined,undefined,undefined,undefined,true); } }