cirsim
Version:
Cirsim Circuit Simulator
337 lines (277 loc) • 8.63 kB
JavaScript
import {Component} from '../Component';
import {ComponentPropertiesDlg} from '../Dlg/ComponentPropertiesDlg';
import {Led} from '../Graphics/Led';
import {Sanitize} from '../Utility/Sanitize';
/**
* Component: LED Bar - 2 to 16 LED's in a vertical bar
* @constructor
*/
export const LEDBar = function() {
Component.call(this);
this.height = 50;
this.width = 20;
this.leds = [];
this.horz = false; // Horizontal option
this.bus = false; // Bus input?
this.color = "blue";
this.lastState = [];
this.setSize(4);
};
LEDBar.prototype = Object.create(Component.prototype);
LEDBar.prototype.constructor = LEDBar;
LEDBar.prototype.prefix = "L";
LEDBar.type = "LEDBar"; ///< Name to use in files
LEDBar.label = "LED Bar"; ///< Label for the palette
LEDBar.desc = "LED Indicator Bar"; ///< Description for the palette
LEDBar.img = "ledbar.png"; ///< Image to use for the palette
LEDBar.description = `<h2>LED Bar</h2><p>The LED Bar component displays from two to
sixteen LEDs in a vertical or horizontal bar that are lighted by values on discrete inputs
or a single bus input. </p>`;
LEDBar.order = 502;
LEDBar.help = 'ledbar';
LEDBar.prototype.setSize = function(size) {
this.size = +size;
this.ensureIO();
}
/**
* Compute the gate result
* @param state
*/
LEDBar.prototype.compute = function(state) {
if(this.bus) {
this.lastState = state[0];
if(this.lastState === undefined) {
this.lastState = [];
}
} else {
this.lastState = state;
}
};
/**
* Clone this component object.
* @returns {LEDBar}
*/
LEDBar.prototype.clone = function() {
const copy = new LEDBar();
copy.size = this.size;
copy.horz = this.horz;
copy.bus = this.bus;
copy.ensureIO();
copy.copyFrom(this);
return copy;
};
/**
* Load this object from an object converted from JSON
* @param obj Object from JSON
*/
LEDBar.prototype.load = function(obj) {
this.color = Sanitize.sanitize(obj["color"]);
if(obj["horz"] !== undefined) {
this.horz = obj['horz'] === true;
}
if(obj['bus'] !== undefined) {
this.bus = obj['bus'] === true;
}
this.setSize(obj["size"]);
Component.prototype.load.call(this, obj);
};
/**
* Create a save object suitable for conversion to JSON for export.
* @returns {*}
*/
LEDBar.prototype.save = function() {
const obj = Component.prototype.save.call(this);
obj.size = this.size;
obj.color = this.color;
obj.horz = this.horz;
obj.bus = this.bus;
return obj;
};
/**
* Ensure the actual number of inputs matches the
* defined bus size.
*/
LEDBar.prototype.ensureIO = function() {
let spacing = 16;
// Input counter
let i = 0;
this.leds = [];
if(this.ins.length > 0) {
//
// Test if we switched input types
// If so, disconnect everything and zero the inputs
//
if(this.ins[0].bus !== this.bus) {
for(i=0; i<this.ins.length; i++) {
this.ins[i].clear();
}
this.ins = [];
}
}
if(this.horz) {
//
// Horizontal configuration
//
this.width = this.size * spacing;
if(this.width < 50) {
this.width = 50;
}
this.height = 20;
let startX = this.size / 2 * spacing - 8;
for(i=0; i<this.size; i++) {
let pinX = startX - i * spacing;
this.leds.push(new Led(pinX, 0, spacing, this.height));
}
if(!this.bus) {
for(i=0; i<this.size; i++) {
let pinX = startX - i * spacing;
let pinLen = 24 - this.height/2;
let inp = null;
if(i < this.ins.length) {
inp = this.ins[i];
} else {
// Add any new pins
inp = this.addIn(pinX, this.height / 2, pinLen);
}
if(inp !== null) {
inp.x = pinX;
inp.y = this.height / 2;
inp.len = pinLen;
inp.orientation = 's';
inp.bus = false;
}
}
} else {
let inp = null;
if(i < this.ins.length) {
inp = this.ins[i];
inp.x = -this.width / 2;
inp.y = 0;
inp.len = 16;
} else {
// Add any new pins
inp = this.addIn(-this.width / 2, 0, 16);
}
inp.orientation = 'w';
inp.bus = true;
inp.autoLen();
}
} else {
//
// Vertical configuration
//
this.height = this.size * spacing;
if(this.height < 50) {
this.height = 50;
}
this.width = 20;
let startY = this.size / 2 * spacing - 8;
for(i=0; i<this.size; i++) {
let pinY = startY - i * spacing;
this.leds.push(new Led(0, pinY, this.width, spacing));
}
if(!this.bus) {
for(i=0; i<this.size; i++) {
let pinY = startY - i * spacing;
let pinLen = 24 - this.width/2;
let inp = null;
if(i < this.ins.length) {
inp = this.ins[i];
inp.x = -this.width / 2;
inp.y = pinY;
inp.len = pinLen;
} else {
// Add any new pins
inp = this.addIn(-this.width / 2, pinY, pinLen);
}
if(inp !== null) {
inp.orientation = 'w';
inp.bus = false;
}
}
} else {
let inp = null;
if(i < this.ins.length) {
inp = this.ins[i];
inp.x = 0;
inp.y = this.height / 2;
inp.len = 16;
} else {
// Add any new pins
inp = this.addIn(0, this.height / 2, 16);
}
inp.orientation = 's';
inp.bus = true;
inp.autoLen();
}
}
if(!this.bus) {
// Delete pins that have ceased to exist
if(i < this.ins.length) {
for( ; i<this.ins.length; i++) {
this.ins[i].clear();
}
this.ins.splice(this.size);
}
}
}
/**
* Draw component object.
* @param context Display context
* @param view View object
*/
LEDBar.prototype.draw = function(context, view) {
//
// Ensure the state is current
//
let i=0;
for( ; i<this.lastState.length && i<this.leds.length; i++) {
let led = this.lastState[i];
this.leds[i].color = led === undefined ? 'undefined' : (led ? this.color : 'black');
}
for( ; i<this.leds.length; i++) {
this.leds[i].color = 'undefined';
}
let background = '#444444';
this.selectStyle(context, view);
this.drawBox(context, background);
for(let i=0; i<this.size; i++) {
this.leds[i].draw(context, this.x, this.y, background);
}
this.drawBox(context, 'none');
this.drawIO(context, view);
};
LEDBar.prototype.properties = function(main) {
const dlg = new ComponentPropertiesDlg(this, main);
// Size
const sizeId = dlg.uniqueId();
let html = `<div class="control1 center"><label for="${sizeId}">Size: </label>
<input class="number" type="text" name="${sizeId}" id="${sizeId}" value="${this.size}"></div>`;
// Color
const colorId = dlg.uniqueId();
html += Led.colorSelector(colorId, this.color);
html += '<div class="control center"><div class="choosers">';
const horzId = dlg.uniqueId();
html += `
<label><input type="radio" name="${horzId}" ${!this.horz ? 'checked' : ''} value="0"> Vertical</label>
<label><input type="radio" name="${horzId}" ${this.horz ? 'checked' : ''} value="1"> Horizontal</label>`;
html += '<br>';
const busId = dlg.uniqueId();
html += `
<label><input type="radio" name="${busId}" ${this.bus ? 'checked' : ''} value="1"> Bus Input</label>
<label><input type="radio" name="${busId}" ${!this.bus ? 'checked' : ''} value="0"> Single Bit Inputs</label>`;
html += '</div></div>';
dlg.extra(html, () => {
const size = parseInt(document.getElementById(sizeId).value);
if(isNaN(size) || size < 2 || size > 16) {
return "Size must be an integer from 2 to 16";
}
return null;
}, () => {
this.color = Sanitize.sanitize(document.getElementById(colorId).value);
this.horz = document.querySelector(`input[name=${horzId}]:checked`).value === '1';
this.bus = document.querySelector(`input[name=${busId}]:checked`).value === '1';
this.setSize(parseInt(document.getElementById(sizeId).value));
});
dlg.open();
};