/* eslint-disable no-shadow */
/* eslint-disable no-negated-condition */
/* eslint-disable no-alert */
/* eslint-disable new-cap */
/* eslint-disable no-undef */
/* eslint-disable eqeqeq */
/* eslint-disable prefer-template */
/* eslint-disable no-param-reassign */
// Most Listeners are stored here
import {
layoutModeGet, tempBuffer, layoutUpdate, setupLayoutModePanelListeners,
} from './layoutMode';
import simulationArea from './simulationArea';
import {
scheduleUpdate, update, updateSelectionsAndPane,
wireToBeCheckedSet, updatePositionSet, updateSimulationSet,
updateCanvasSet, gridUpdateSet, errorDetectedSet,
} from './engine';
import { changeScale, findDimensions } from './canvasApi';
import { scheduleBackup } from './data/backupCircuit';
import { hideProperties, deleteSelected, uxvar, fullView, createElement, exitFullView, escapeHtml } from './ux';
import {
updateRestrictedElementsList, updateRestrictedElementsInScope, hideRestricted, showRestricted,
} from './restrictedElementDiv';
import { removeMiniMap, updatelastMinimapShown } from './minimap';
import undo from './data/undo';
import redo from "./data/redo";
import { copy, paste, selectAll } from './events';
// Import save from './data/save';
import { verilogModeGet } from './Verilog2CV';
import { setupTimingListeners } from './plotArea';
import { getProjectName } from './data/save';
import logixFunction from './data';
import createSaveAsImgPrompt from './data/saveImage';
const unit = 10;
let coordinate;
const returnCoordinate = {
x: 0,
y: 0,
};
var uniqid = {
modulePropertyInner: '',
PlotAreaId: '',
plotID: '',
tdLog: '',
};
var currDistance = 0;
var distance = 0;
var pinchZ = 0;
var centreX = 0;
var centreY = 0;
var timeout;
var lastTap = 0;
var initX;
var initY;
var currX;
var currY;
var navMenuButtonHeight;
var navMenuButton;
var smallnavbar;
var isCopy = false;
/**
*
* @param {event} e
* @param {elementId} elementId
* Function to drag element of selected ID
*/
function dragStart(e, elementId) {
initX = e.touches[0].clientX - elementId.offsetLeft;
initY = e.touches[0].clientY - elementId.offsetTop;
}
function dragMove(e, elementId) {
currY = e.touches[0].clientY - initY;
currX = e.touches[0].clientX - initX;
elementId.style.left = currX + 'px';
elementId.style.top = currY + 'px';
}
function dragEnd() {
initX = currX;
initY = currY;
}
/**
*
* @param {event} e
* function for double click or double tap
*/
function onDoubleClickorTap(e) {
updateCanvasSet(true);
if (simulationArea.lastSelected && simulationArea.lastSelected.dblclick !== undefined) {
simulationArea.lastSelected.dblclick();
} else if (!simulationArea.shiftDown) {
simulationArea.multipleObjectSelections = [];
}
scheduleUpdate(2);
e.preventDefault();
}
/**
*
* @param {event} e
* function to detect tap and double tap
*/
function getTap(e) {
const currentTime = new Date().getTime();
const tapLength = currentTime - lastTap;
clearTimeout(timeout);
if (tapLength < 500 && tapLength > 0) {
onDoubleClickorTap(e);
} else {
// Single tap
}
openCurrMenu(-1);
lastTap = currentTime;
e.preventDefault();
}
const isIe = (navigator.userAgent.toLowerCase().indexOf('msie') != -1 || navigator.userAgent.toLowerCase().indexOf('trident') != -1);
// Function to getCoordinate
// *If touch is enable then it will return touch coordinate
// *else it will return mouse coordinate
//
export function getCoordinate(e) {
if (simulationArea.touch) {
returnCoordinate.x = e.touches[0].clientX;
returnCoordinate.y = e.touches[0].clientY;
return returnCoordinate;
}
if (!simulationArea.touch) {
returnCoordinate.x = e.clientX;
returnCoordinate.y = e.clientY;
return returnCoordinate;
}
return returnCoordinate;
}
// Function for Pinch zoom
// *This function is used to ZoomIN and Zoomout on Simulator using touch
//
export function pinchZoom(e, globalScope) {
e.preventDefault();
gridUpdateSet(true);
scheduleUpdate();
updateSimulationSet(true);
updatePositionSet(true);
updateCanvasSet(true);
// Calculating distance between touch to see if its pinchIN or pinchOut
distance = Math.sqrt((e.touches[1].clientX - e.touches[0].clientX) ** 2, (e.touches[1].clientY - e.touches[0].clientY) ** 2);
if (distance >= currDistance) {
pinchZ += 0.02;
currDistance = distance;
} else if (currDistance >= distance) {
pinchZ -= 0.02;
currDistance = distance;
}
if (pinchZ >= 2) {
pinchZ = 2;
}
else if (pinchZ <= 0.5) {
pinchZ = 0.5;
}
const oldScale = globalScope.scale;
globalScope.scale = Math.max(0.5, Math.min(4 * DPR, pinchZ * 3));
globalScope.scale = Math.round(globalScope.scale * 10) / 10;
// This is not working as expected
centreX = (e.touches[0].clientX + e.touches[1].clientX) / 2;
centreY = (e.touches[0].clientY + e.touches[1].clientY) / 2;
const rect = simulationArea.canvas.getBoundingClientRect();
const RawX = (centreX - rect.left) * DPR;
const RawY = (centreY - rect.top) * DPR;
const Xf = Math.round(((RawX - globalScope.ox) / globalScope.scale) / unit);
const Yf = Math.round(((RawY - globalScope.ox) / globalScope.scale) / unit);
const currCentreX = Math.round(Xf / unit) * unit;
const currCentreY = Math.round(Yf / unit) * unit;
globalScope.ox = Math.round(currCentreX * (globalScope.scale - oldScale));
globalScope.oy = Math.round(currCentreY * (globalScope.scale - oldScale));
gridUpdateSet(true);
scheduleUpdate(1);
}
//
// Function to start the pan in simulator
// Works for both touch and Mouse
// For now variable name starts from mouse like mouseDown are used both
// touch and mouse will change in future
//
function panStart(e) {
coordinate = getCoordinate(e);
simulationArea.mouseDown = true;
// Deselect Input
if (document.activeElement instanceof HTMLElement) {
document.activeElement.blur();
}
errorDetectedSet(false);
updateSimulationSet(true);
updatePositionSet(true);
updateCanvasSet(true);
simulationArea.lastSelected = undefined;
simulationArea.selected = false;
simulationArea.hover = undefined;
const rect = simulationArea.canvas.getBoundingClientRect();
simulationArea.mouseDownRawX = (coordinate.x - rect.left) * DPR;
simulationArea.mouseDownRawY = (coordinate.y - rect.top) * DPR;
simulationArea.mouseDownX = Math.round(((simulationArea.mouseDownRawX - globalScope.ox) / globalScope.scale) / unit) * unit;
simulationArea.mouseDownY = Math.round(((simulationArea.mouseDownRawY - globalScope.oy) / globalScope.scale) / unit) * unit;
if (simulationArea.touch) {
simulationArea.mouseX = simulationArea.mouseDownX;
simulationArea.mouseY = simulationArea.mouseDownY;
}
simulationArea.oldx = globalScope.ox;
simulationArea.oldy = globalScope.oy;
e.preventDefault();
scheduleBackup();
scheduleUpdate(1);
$('.dropdown.open').removeClass('open');
}
//
// Function to pan in simulator
// Works for both touch and Mouse
// For now variable name starts from mouse like mouseDown are used both
// touch and mouse will change in future
//
function panMove(e) {
// If only one it touched
// pan left or right
if (!simulationArea.touch || e.touches.length === 1) {
coordinate = getCoordinate(e);
const rect = simulationArea.canvas.getBoundingClientRect();
simulationArea.mouseRawX = (coordinate.x - rect.left) * DPR;
simulationArea.mouseRawY = (coordinate.y - rect.top) * DPR;
simulationArea.mouseXf = (simulationArea.mouseRawX - globalScope.ox) / globalScope.scale;
simulationArea.mouseYf = (simulationArea.mouseRawY - globalScope.oy) / globalScope.scale;
simulationArea.mouseX = Math.round(simulationArea.mouseXf / unit) * unit;
simulationArea.mouseY = Math.round(simulationArea.mouseYf / unit) * unit;
updateCanvasSet(true);
if (simulationArea.lastSelected && (simulationArea.mouseDown || simulationArea.lastSelected.newElement)) {
updateCanvasSet(true);
let fn;
if (simulationArea.lastSelected == globalScope.root) {
fn = function () {
updateSelectionsAndPane();
};
} else {
fn = function () {
if (simulationArea.lastSelected) {
simulationArea.lastSelected.update();
}
};
}
scheduleUpdate(0, 20, fn);
} else {
scheduleUpdate(0, 200);
}
}
// If two fingures are touched
// pinchZoom
if (simulationArea.touch && e.touches.length === 2) {
pinchZoom(e, globalScope);
}
}
// Function for Panstop on simulator
// *For now variable name starts with mouse like mouseDown are used both
// touch and mouse will change in future
//
function panStop(e) {
simulationArea.mouseDown = false;
if (!lightMode) {
updatelastMinimapShown();
setTimeout(removeMiniMap, 2000);
}
errorDetectedSet(false);
updateSimulationSet(true);
updatePositionSet(true);
updateCanvasSet(true);
gridUpdateSet(true);
wireToBeCheckedSet(1);
scheduleUpdate(1);
simulationArea.mouseDown = false;
// eslint-disable-next-line no-plusplus
for (let i = 0; i < 2; i++) {
updatePositionSet(true);
wireToBeCheckedSet(1);
update();
}
errorDetectedSet(false);
updateSimulationSet(true);
updatePositionSet(true);
updateCanvasSet(true);
gridUpdateSet(true);
wireToBeCheckedSet(1);
scheduleUpdate(1);
// Var rect = simulationArea.canvas.getBoundingClientRect();
if (!(simulationArea.mouseRawX < 0 || simulationArea.mouseRawY < 0 || simulationArea.mouseRawX > width || simulationArea.mouseRawY > height)) {
uxvar.smartDropXX = simulationArea.mouseX + 100; // Math.round(((simulationArea.mouseRawX - globalScope.ox+100) / globalScope.scale) / unit) * unit;
uxvar.smartDropYY = simulationArea.mouseY - 50; // Math.round(((simulationArea.mouseRawY - globalScope.oy+100) / globalScope.scale) / unit) * unit;
}
if (simulationArea.touch) {
// small hack so Current circuit element should not spwan above last circuit element
if(!isCopy) {
findDimensions(globalScope);
simulationArea.mouseX = 100 + simulationArea.maxWidth || 0;
simulationArea.mouseY = simulationArea.minHeight || 0;
getTap(e);
}
}
}
export default function startListeners() {
$('#deleteSelected').on('click', () => {
deleteSelected();
});
$('#zoomIn').on('click', () => {
changeScale(0.2, 'zoomButton', 'zoomButton', 2);
});
$('#zoomOut').on('click', () => {
changeScale(-0.2, 'zoomButton', 'zoomButton', 2);
});
$('#undoButton').on('click', () => {
undo();
});
$('#redoButton').on('click',() => {
redo();
})
$('#viewButton').on('click',() => {
fullView();
});
$(document).on('keyup', (e) => {
if (e.key === "Escape") exitFullView();
});
$('#projectName').on('click',() => {
simulationArea.lastSelected = globalScope.root;
setTimeout(() => {
document.getElementById('projname').select();
}, 100);
});
/* Makes tabs reordering possible by making them sortable */
$('#tabsBar').sortable({
containment: 'parent',
items: '> div',
revert: false,
opacity: 0.5,
tolerance: 'pointer',
placeholder: 'placeholder',
forcePlaceholderSize: true,
});
document.getElementById('simulationArea').addEventListener('mousedown', (e) => {
simulationArea.touch = false;
panStart(e);
});
document.getElementById('simulationArea').addEventListener('mouseup', () => {
if (simulationArea.lastSelected) {
simulationArea.lastSelected.newElement = false;
}
//
// Handling restricted circuit elements
//
if (simulationArea.lastSelected && restrictedElements.includes(simulationArea.lastSelected.objectType) && !globalScope.restrictedCircuitElementsUsed.includes(simulationArea.lastSelected.objectType)) {
globalScope.restrictedCircuitElementsUsed.push(simulationArea.lastSelected.objectType);
updateRestrictedElementsList();
}
// Deselect multible elements with click
if (!simulationArea.shiftDown && simulationArea.multipleObjectSelections.length > 0
) {
if (
!simulationArea.multipleObjectSelections.includes(simulationArea.lastSelected)
) {
simulationArea.multipleObjectSelections = [];
}
}
});
document.getElementById('simulationArea').addEventListener('mousemove', (e) => {
simulationArea.touch = false;
panMove(e);
});
document.getElementById('simulationArea').addEventListener('mouseup', (e) => {
simulationArea.touch = false;
panStop(e);
});
// Implementating touch listerners
// *All Main basic touch listerners are
// present here
//
document.getElementById('simulationArea').addEventListener('touchstart', (e) => {
simulationArea.touch = true;
panStart(e);
});
document.getElementById('simulationArea').addEventListener('touchmove', (e) => {
simulationArea.touch = true;
panMove(e);
});
document.getElementById('simulationArea').addEventListener('touchend', (e) => {
simulationArea.touch = true;
panStop(e);
});
window.addEventListener('keyup', (e) => {
scheduleUpdate(1);
simulationArea.shiftDown = e.shiftKey;
if (e.keyCode == 16) {
simulationArea.shiftDown = false;
}
if (e.key == 'Meta' || e.key == 'Control') {
simulationArea.controlDown = false;
}
});
window.addEventListener('keydown', (e) => {
if (document.activeElement.tagName == 'INPUT') {
return;
}
if (document.activeElement != document.body) {
return;
}
simulationArea.shiftDown = e.shiftKey;
if (e.key == 'Meta' || e.key == 'Control') {
simulationArea.controlDown = true;
}
if (simulationArea.controlDown && e.key.charCodeAt(0) == 122 && !simulationArea.shiftDown) { // detect the special CTRL-Z code
undo();
}
if (simulationArea.controlDown && e.key.charCodeAt(0) == 122 && simulationArea.shiftDown) { // detect the special Cmd + shift + z code (macOs)
redo();
}
if (simulationArea.controlDown && e.key.charCodeAt(0) == 121 && !simulationArea.shiftDown) { // detect the special ctrl + Y code (windows)
redo();
}
if (listenToSimulator) {
// If mouse is focusing on input element, then override any action
// if($(':focus').length){
// return;
// }
if (document.activeElement.tagName == 'INPUT' || simulationArea.mouseRawX < 0 || simulationArea.mouseRawY < 0 || simulationArea.mouseRawX > width || simulationArea.mouseRawY > height) {
return;
}
// HACK TO REMOVE FOCUS ON PROPERTIES
if (document.activeElement.type == 'number') {
hideProperties();
showProperties(simulationArea.lastSelected);
}
errorDetectedSet(false);
updateSimulationSet(true);
updatePositionSet(true);
simulationArea.shiftDown = e.shiftKey;
if (e.key == 'Meta' || e.key == 'Control') {
simulationArea.controlDown = true;
}
// Zoom in (+)
if ((simulationArea.controlDown && (e.keyCode == 187 || e.keyCode == 171)) || e.keyCode == 107) {
e.preventDefault();
// eslint-disable-next-line no-use-before-define
ZoomIn();
}
// Zoom out (-)
if ((simulationArea.controlDown && (e.keyCode == 189 || e.keyCode == 173)) || e.keyCode == 109) {
e.preventDefault();
// eslint-disable-next-line no-use-before-define
ZoomOut();
}
if (simulationArea.mouseRawX < 0 || simulationArea.mouseRawY < 0 || simulationArea.mouseRawX > width || simulationArea.mouseRawY > height) {
return;
}
scheduleUpdate(1);
updateCanvasSet(true);
wireToBeCheckedSet(1);
// Needs to be deprecated, moved to more recent listeners
if (simulationArea.controlDown && (e.key == 'C' || e.key == 'c')) {
// SimulationArea.copyList=simulationArea.multipleObjectSelections.slice();
// if(simulationArea.lastSelected&&simulationArea.lastSelected!==simulationArea.root&&!simulationArea.copyList.contains(simulationArea.lastSelected)){
// simulationArea.copyList.push(simulationArea.lastSelected);
// }
// copy(simulationArea.copyList);
}
if (simulationArea.lastSelected && simulationArea.lastSelected.keyDown) {
if (e.key.toString().length == 1 || e.key.toString() == 'Backspace' || e.key.toString() == 'Enter') {
simulationArea.lastSelected.keyDown(e.key.toString());
e.cancelBubble = true;
e.returnValue = false;
// E.stopPropagation works in Firefox.
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
return;
}
}
if (simulationArea.lastSelected && simulationArea.lastSelected.keyDown2) {
if (e.key.toString().length == 1) {
simulationArea.lastSelected.keyDown2(e.key.toString());
return;
}
}
if (simulationArea.lastSelected && simulationArea.lastSelected.keyDown3) {
if (e.key.toString() != 'Backspace' && e.key.toString() != 'Delete') {
simulationArea.lastSelected.keyDown3(e.key.toString());
return;
}
}
if (e.keyCode == 16) {
simulationArea.shiftDown = true;
if (simulationArea.lastSelected && !simulationArea.lastSelected.keyDown && simulationArea.lastSelected.objectType != 'Wire' && simulationArea.lastSelected.objectType != 'CircuitElement' && !simulationArea.multipleObjectSelections.contains(simulationArea.lastSelected)) {
simulationArea.multipleObjectSelections.push(simulationArea.lastSelected);
}
}
// Detect offline save shortcut (CTRL+SHIFT+S)
if (simulationArea.controlDown && e.keyCode == 83 && simulationArea.shiftDown) {
saveOffline();
e.preventDefault();
}
// Detect Select all Shortcut
if (simulationArea.controlDown && (e.keyCode == 65 || e.keyCode == 97)) {
selectAll();
e.preventDefault();
}
// Deselect all Shortcut
if (e.keyCode == 27) {
simulationArea.multipleObjectSelections = [];
simulationArea.lastSelected = undefined;
e.preventDefault();
}
if ((e.keyCode == 113 || e.keyCode == 81) && simulationArea.lastSelected != undefined) {
if (simulationArea.lastSelected.bitWidth !== undefined) {
simulationArea.lastSelected.newBitWidth(parseInt(prompt('Enter new bitWidth'), 10));
}
}
if (simulationArea.controlDown && (e.key == 'T' || e.key == 't')) {
// E.preventDefault(); //browsers normally open a new tab
simulationArea.changeClockTime(prompt('Enter Time:'));
}
}
if (e.keyCode == 8 || e.key == 'Delete') {
deleteSelected();
}
}, true);
document.getElementById('simulationArea').addEventListener('dblclick', (e) => {
onDoubleClickorTap(e);
});
function MouseScroll(event) {
updateCanvasSet(true);
event.preventDefault();
// eslint-disable-next-line vars-on-top
// eslint-disable-next-line no-var
var deltaY = event.wheelDelta ? event.wheelDelta : -event.detail;
event.preventDefault();
// eslint-disable-next-line no-redeclare
var deltaY = event.wheelDelta ? event.wheelDelta : -event.detail;
const direction = deltaY > 0 ? 1 : -1;
// eslint-disable-next-line no-use-before-define
handleZoom(direction);
updateCanvasSet(true);
gridUpdateSet(true);
if (layoutModeGet()) {
layoutUpdate();
} else {
update();
} // Schedule update not working, this is INEFFICIENT
}
document.getElementById('simulationArea').addEventListener('mousewheel', MouseScroll);
document.getElementById('simulationArea').addEventListener('DOMMouseScroll', MouseScroll);
document.addEventListener('cut', (e) => {
if (verilogModeGet()) {
return;
}
if (document.activeElement.tagName == 'INPUT') {
return;
}
if (document.activeElement.tagName != 'BODY') {
return;
}
if (listenToSimulator) {
simulationArea.copyList = simulationArea.multipleObjectSelections.slice();
if (simulationArea.lastSelected && simulationArea.lastSelected !== simulationArea.root && !simulationArea.copyList.contains(simulationArea.lastSelected)) {
simulationArea.copyList.push(simulationArea.lastSelected);
}
const textToPutOnClipboard = copy(simulationArea.copyList, true);
// Updated restricted elements
updateRestrictedElementsInScope();
localStorage.setItem('clipboardData', textToPutOnClipboard);
e.preventDefault();
if (textToPutOnClipboard == undefined) {
return;
}
if (isIe) {
window.clipboardData.setData('Text', textToPutOnClipboard);
} else {
e.clipboardData.setData('text/plain', textToPutOnClipboard);
}
}
});
document.addEventListener('copy', (e) => {
if (verilogModeGet()) {
return;
}
if (document.activeElement.tagName == 'INPUT') {
return;
}
if (document.activeElement.tagName != 'BODY') {
return;
}
if (listenToSimulator) {
simulationArea.copyList = simulationArea.multipleObjectSelections.slice();
if (simulationArea.lastSelected && simulationArea.lastSelected !== simulationArea.root && !simulationArea.copyList.contains(simulationArea.lastSelected)) {
simulationArea.copyList.push(simulationArea.lastSelected);
}
const textToPutOnClipboard = copy(simulationArea.copyList);
// Updated restricted elements
updateRestrictedElementsInScope();
localStorage.setItem('clipboardData', textToPutOnClipboard);
e.preventDefault();
if (textToPutOnClipboard == undefined) {
return;
}
if (isIe) {
window.clipboardData.setData('Text', textToPutOnClipboard);
} else {
e.clipboardData.setData('text/plain', textToPutOnClipboard);
}
}
});
document.addEventListener('paste', (e) => {
if (document.activeElement.tagName == 'INPUT') {
return;
}
if (document.activeElement.tagName != 'BODY') {
return;
}
if (listenToSimulator) {
let data;
if (isIe) {
data = window.clipboardData.getData('Text');
} else {
data = e.clipboardData.getData('text/plain');
}
paste(data);
// Updated restricted elements
updateRestrictedElementsInScope();
e.preventDefault();
}
});
// 'drag and drop' event listener for subcircuit elements in layout mode
$('#subcircuitMenu').on('dragstop', '.draggableSubcircuitElement', function (event, ui) {
const sideBarWidth = $('#guide_1')[0].clientWidth;
let tempElement;
if (ui.position.top > 10 && ui.position.left > sideBarWidth) {
// Make a shallow copy of the element with the new coordinates
tempElement = globalScope[this.dataset.elementName][this.dataset.elementId];
// Changing the coordinate doesn't work yet, nodes get far from element
tempElement.x = ui.position.left - sideBarWidth;
tempElement.y = ui.position.top;
// eslint-disable-next-line no-restricted-syntax
for (const node of tempElement.nodeList) {
node.x = ui.position.left - sideBarWidth;
node.y = ui.position.top;
}
tempBuffer.subElements.push(tempElement);
this.parentElement.removeChild(this);
}
});
restrictedElements.forEach((element) => {
$(`#${element}`).mouseover(() => {
showRestricted();
});
$(`#${element}`).mouseout(() => {
hideRestricted();
});
});
$('.search-input').on('keyup', function () {
const parentElement = $(this).parent().parent();
const closeButton = $('.search-close', parentElement);
const searchInput = $('.search-input', parentElement);
const searchResults = $('.search-results', parentElement);
const menu = $('.accordion', parentElement);
searchResults.css('display', 'block');
closeButton.css('display', 'block');
menu.css('display', 'none');
const value = $(this).val().toLowerCase();
closeButton.on('click', () => {
searchInput.val('');
menu.css('display', 'block');
searchResults.css('display', 'none');
closeButton.css('display', 'none');
});
if (value.length === 0) {
menu.css('display', 'block');
searchResults.css('display', 'none');
closeButton.css('display', 'none');
return;
}
let htmlIcons = '';
const result = elementPanelList.filter(ele => ele.toLowerCase().includes(value));
var finalResult = [];
for(const j in result) {
if (Object.prototype.hasOwnProperty.call(result, j)) {
for (const category in elementHierarchy) {
if(Object.prototype.hasOwnProperty.call(elementHierarchy, category)) {
const categoryData = elementHierarchy[category];
for (let i = 0; i < categoryData.length; i++) {
if(result[j] == categoryData[i].label) {
finalResult.push(categoryData[i]);
}
}
}
}
}
}
if(!finalResult.length) searchResults.text('No elements found ...');
else {
finalResult.forEach( e => htmlIcons += createIcon(e));
searchResults
.html(htmlIcons);
$('.filterElements').mousedown(createElement);
}
});
function createIcon(element) {
return `<div class="${element.name} icon logixModules filterElements" id="${element.name}" title="${element.label}">
<img src= "/img/${element.name}.svg" alt="element's image" >
</div>`;
}
// eslint-disable-next-line no-use-before-define
zoomSliderListeners();
setupLayoutModePanelListeners();
if (!embed) {
setupTimingListeners();
}
/**
* Listerners of CircuitElement panel ,properties panel,time diagram, quichbtn
* Some users use touch on laptop so to scroll imp panel on desktop UI
*/
const modulePropertyListners = document.getElementById('moduleProperty');
const moduleQueryslector = document.querySelector('#moduleProperty');
const circuitElementListner = document.getElementById('guide_1');
const CircuitElementQuerySelector = document.querySelector('#guide_1');
const QuickPanelListner = document.getElementById('quick-btn-id');
const QuickPanelQuerySelector = document.querySelector('#quick-btn-id');
const timingDiagramListner = document.getElementById('time-Diagram');
const timingDiagramQuerySelector = document.querySelector('#time-Diagram');
const layoutListner = document.getElementById('layoutDialog');
const layoutQuerySelector = document.querySelector('#layoutDialog');
const layoutElementPanelListner = document.getElementsByClassName('layoutElementPanel')[0];
// const colorThemesDialogListner = document.getElementById('colorThemesDialog');
moduleQueryslector.addEventListener('touchstart', (e) => {
dragStart(e, modulePropertyListners);
});
moduleQueryslector.addEventListener('touchmove', (e) => {
dragMove(e, modulePropertyListners);
});
moduleQueryslector.addEventListener('touchend', () => {
dragEnd();
});
CircuitElementQuerySelector.addEventListener('touchstart', (e) => {
dragStart(e, circuitElementListner);
});
CircuitElementQuerySelector.addEventListener('touchmove', (e) => {
dragMove(e, circuitElementListner);
});
CircuitElementQuerySelector.addEventListener('touchend', () => {
dragEnd();
});
QuickPanelQuerySelector.addEventListener('touchstart', (e) => {
dragStart(e, QuickPanelQuerySelector);
});
QuickPanelQuerySelector.addEventListener('touchmove', (e) => {
dragMove(e, QuickPanelListner);
});
QuickPanelQuerySelector.addEventListener('touchend', () => {
dragEnd();
});
timingDiagramQuerySelector.addEventListener('touchstart', (e) => {
$('.timing-diagram-panel').draggable().draggable('enable');
timingDiagramListner.style.position = 'absolute';
dragStart(e, timingDiagramListner);
});
timingDiagramQuerySelector.addEventListener('touchmove', (e) => {
dragMove(e, timingDiagramListner);
});
timingDiagramQuerySelector.addEventListener('touchend', () => {
dragEnd();
});
layoutQuerySelector.addEventListener('touchstart', (e) => {
$('.timing-diagram-panel').draggable().draggable('enable');
timingDiagramListner.style.position = 'absolute';
dragStart(e, layoutListner);
});
layoutQuerySelector.addEventListener('touchmove', (e) => {
dragMove(e, layoutListner);
});
layoutQuerySelector.addEventListener('touchend', () => {
dragEnd();
});
layoutElementPanelListner.addEventListener('touchstart', (e) => {
$('.timing-diagram-panel').draggable().draggable('enable');
timingDiagramListner.style.position = 'absolute';
dragStart(e, layoutElementPanelListner);
});
layoutElementPanelListner.addEventListener('touchmove', (e) => {
dragMove(e, layoutElementPanelListner);
});
layoutElementPanelListner.addEventListener('touchend', () => {
dragEnd();
});
}
function resizeTabs() {
const $windowsize = $('body').width();
const $sideBarsize = $('.side').width();
const $maxwidth = ($windowsize - $sideBarsize);
$('#tabsBar div').each(function () {
$(this).css({ 'max-width': $maxwidth - 30 });
});
}
window.addEventListener('resize', resizeTabs);
resizeTabs();
$(() => {
$('[data-bs-toggle="tooltip"]').tooltip();
});
// Direction is only 1 or -1
function handleZoom(direction) {
if (globalScope.scale > 0.5 * DPR) {
changeScale(direction * 0.1 * DPR);
} else if (globalScope.scale < 4 * DPR) {
changeScale(direction * 0.1 * DPR);
}
gridUpdateSet(true);
scheduleUpdate();
}
export function ZoomIn() {
handleZoom(1);
}
export function ZoomOut() {
handleZoom(-1);
}
function zoomSliderListeners() {
document.getElementById('customRange1').value = 5;
// eslint-disable-next-line no-use-before-define
document.getElementById('simulationArea').addEventListener('DOMMouseScroll', zoomSliderScroll);
// eslint-disable-next-line no-use-before-define
document.getElementById('simulationArea').addEventListener('mousewheel', zoomSliderScroll);
let curLevel = document.getElementById('customRange1').value;
$(document).on('input change', '#customRange1', function () {
const newValue = $(this).val();
const changeInScale = newValue - curLevel;
updateCanvasSet(true);
changeScale(changeInScale * 0.1, 'zoomButton', 'zoomButton', 3);
gridUpdateSet(true);
curLevel = newValue;
});
function zoomSliderScroll(e) {
let zoomLevel = document.getElementById('customRange1').value;
const deltaY = e.wheelDelta ? e.wheelDelta : -e.detail;
const directionY = deltaY > 0 ? 1 : -1;
if (directionY > 0) {
zoomLevel++;
} else {
zoomLevel--;
}
if (zoomLevel >= 45) {
zoomLevel = 45;
document.getElementById('customRange1').value = 45;
} else if (zoomLevel <= 0) {
zoomLevel = 0;
document.getElementById('customRange1').value = 0;
} else {
document.getElementById('customRange1').value = zoomLevel;
curLevel = zoomLevel;
}
}
function sliderZoomButton(direction) {
const zoomSlider = $('#customRange1');
let currentSliderValue = parseInt(zoomSlider.val(), 10);
if (direction === -1) {
currentSliderValue--;
} else {
currentSliderValue++;
}
zoomSlider.val(currentSliderValue).change();
}
$('#decrement').click(() => {
sliderZoomButton(-1);
});
$('#increment').click(() => {
sliderZoomButton(1);
});
var buttoncolor = 'var(--touch-menu)';
/**
* Mobile navbar
*/
smallnavbar = document.getElementById('smallNavbarMenu-btn');
function ChangeIconColor(Id, color) {
if(Id.style.backgroundColor === color) {
Id.style.backgroundColor = '';
}
else {
Id.style.backgroundColor = color;
}
}
smallnavbar.addEventListener('touchstart', (e) => {
ChangeIconColor(smallnavbar, buttoncolor);
smallnavbar.classList.toggle('active');
e.preventDefault();
});
smallnavbar.addEventListener('touchend', (e) => {
ChangeIconColor(smallnavbar, '');
openCloseSmallNavbar();
e.preventDefault();
});
smallnavbar.addEventListener('mousedown', (e) => {
ChangeIconColor(smallnavbar, buttoncolor);
smallnavbar.classList.toggle('active');
e.preventDefault();
});
smallnavbar.addEventListener('mouseup', (e) => {
ChangeIconColor(smallnavbar, '');
openCloseSmallNavbar();
e.preventDefault();
});
function openCloseSmallNavbar() {
navMenuButtonHeight = document.getElementsByClassName('smallscreen-navbar')[0].offsetHeight;
navMenuButton = document.getElementsByClassName('smallscreen-navbar');
if(navMenuButtonHeight === 0) {
navMenuButton[0].style.height = '100%';
}
else {
navMenuButton[0].style.height = '0';
}
var projectname = document.getElementById('ProjectID');
var Uniqueprojectname = escapeHtml(getProjectName()) || 'Untitled';
projectname.innerHTML = `<p>${Uniqueprojectname}<p>`;
}
/** Improved Collapsible navbar */
var smallScreemInner = document.getElementsByClassName('smallscreen-navbar-inner');
var smallNavbarUl = document.getElementsByClassName('smallNavbar-navbar-ul');
var ulicon = document.getElementsByClassName('ulicon');
function NavCollapsible(index) {
for(var i = 0; i < smallNavbarUl.length - 1; i++) {
if(i !== index) {
ulicon[i].classList.remove('active');
smallScreemInner[i].style.height = '0%';
}
}
if(smallScreemInner[index].style.height === '100%') {
smallScreemInner[index].style.height = '0%';
ulicon[index].classList.remove('active');
}
else {
smallScreemInner[index].style.height = '100%';
ulicon[index].classList.toggle('active');
}
}
for(var i = 0; i < smallNavbarUl.length; i++) {
(function(index) {
smallNavbarUl[index].addEventListener('click', () => {
NavCollapsible(index);
});
}(i));
}
var SmallScreenLi = document.getElementsByClassName('SmallScreen-Navbar-li');
for(var j = 0; j < SmallScreenLi.length; j++) {
(function(index) {
SmallScreenLi[index].addEventListener('click', (e) => {
onTapColor(SmallScreenLi, index, '#A0937D');
onTapSmallNavbar(index);
setTimeout(() => {
onTapColor(SmallScreenLi, index, ''); }, 100);
e.preventDefault();
});
}(j));
}
// Function for Touchmenu
var TouchMenuButton = document.getElementsByClassName('touchMenuIcon');
var panelclose = document.getElementsByClassName('panelclose');
for(var touchi = 0; touchi < TouchMenuButton.length; touchi++) {
(function(index) {
TouchMenuButton[index].addEventListener('touchstart', (e) => {
onTapColor(TouchMenuButton, index, buttoncolor);
openCurrMenu(index);
e.preventDefault();
});
TouchMenuButton[index].addEventListener('mousedown', (e) => {
onTapColor(TouchMenuButton, index, buttoncolor);
openCurrMenu(index);
e.preventDefault();
});
panelclose[index].addEventListener('touchstart', (e) => {
onTapColor(TouchMenuButton, index, buttoncolor);
openCurrMenu(index);
e.preventDefault();
});
panelclose[index].addEventListener('mousedown', (e) => {
onTapColor(TouchMenuButton, index, buttoncolor);
openCurrMenu(index);
e.preventDefault();
});
}(touchi));
}
/** Function for QuicKMenu */
var quickMenu = document.getElementsByClassName('quicMenu-align');
// here lenght-2 is done because last two button are used for diff purpose
for(var quickmenui = 0; quickmenui < quickMenu.length - 2; quickmenui++) {
(function(index) {
quickMenu[index].addEventListener('click', (e) => {
onTapColor(quickMenu, index, buttoncolor);
onQuickmenuTap(index);
setTimeout(() => {
onTapColor(quickMenu, index, ''); }, 100);
e.preventDefault();
});
}(quickmenui));
}
quickMenu[6].addEventListener('click', (e) => {
onTapColor(quickMenu, 6, buttoncolor);
if(simulationArea.shiftDown == false) {
simulationArea.shiftDown = true;
}
else {
simulationArea.shiftDown = false;
e.preventDefault();
}
});
// Function for live Menu
// Undo,Delete,Fit to screen
//
var liveMenu = document.getElementsByClassName('liveMenuIcon');
for(var liveMenui = 0; liveMenui < liveMenu.length; liveMenui++) {
(function(index) {
liveMenu[index].addEventListener('touchstart', (e) => {
onTapColor(liveMenu, index, buttoncolor);
e.preventDefault();
});
liveMenu[index].addEventListener('touchend', (e) => {
onTapColor(liveMenu, index, '');
onTapliveMenu(index);
e.preventDefault();
});
liveMenu[index].addEventListener('mousedown', (e) => {
onTapColor(liveMenu, index, buttoncolor);
e.preventDefault();
});
liveMenu[index].addEventListener('mouseup', (e) => {
onTapColor(liveMenu, index, '');
onTapliveMenu(index);
e.preventDefault();
});
}(liveMenui));
}
}
/**
*
* Function to return id or class of panel according to screen width
*/
export function currentScreen() {
if (window.screen.width > 1000) {
uniqid.modulePropertyInner = '#moduleProperty-inner';
uniqid.PlotAreaId = 'plotArea';
uniqid.plotID = 'plot';
uniqid.tdLog = '#timing-diagram-log';
}
else {
uniqid.modulePropertyInner = '#moduleProperty-inner-2';
uniqid.PlotAreaId = 'plotArea-touchpanel';
uniqid.plotID = 'plot-touchpanel';
uniqid.tdLog = '#touch-timing-diagram-log';
}
return uniqid;
}
function getID(index) {
switch (index) {
case 0: return document.getElementById('TouchCe-panel');
case 1: return document.getElementById('touchElement-property');
case 2: return document.getElementById('touchtD-popover');
case 3: return document.getElementById('quickmenu-Popover');
default: break;
}
return 0;
}
function openCurrMenu(index) {
if (index != -1) {
$('#Help').removeClass('show');
var element = getID(index);
if (element.style.visibility === 'visible') {
element.style.visibility = 'hidden';
} else {
element.style.visibility = 'visible';
}
}
for (var i = 0; i < 4; i++) {
if (i !== index) {
var closelemnt = getID(i);
closelemnt.style.visibility = 'hidden';
}
}
}
/**
* Function For Menu Button Color
*/
function onTapColor(classList, currentIndex, color) {
if(classList[currentIndex].style.backgroundColor === color) {
classList[currentIndex].style.backgroundColor = '';
}
else {
classList[currentIndex].style.backgroundColor = color;
}
for(var i = 0; i < classList.length; i++) {
if(i != currentIndex) {
classList[i].style.backgroundColor = '';
}
}
}
function onTapliveMenu(index) {
switch (index) {
case 0: globalScope.centerFocus(false);
updateCanvasSet(true);
gridUpdateSet(true);
break;
case 1: deleteSelected();
break;
case 2: undo();
break;
case 3: redo();
break;
default:
break;
}
}
function onQuickmenuTap(i) {
switch (i) {
case 0: logixFunction.save();
break;
case 1: logixFunction.saveOffline();
break;
case 2: logixFunction.createOpenLocalPrompt();
break;
case 3: createSaveAsImgPrompt();
break;
case 4: document.execCommand('copy');
simulationArea.shiftDown = false;
isCopy = true;
break;
case 5: paste(localStorage.getItem('clipboardData'));
isCopy = false;
break;
default:
break;
}
}
function onTapSmallNavbar(i) {
switch (i) {
case 0: logixFunction.newProject();
closeNavmenu();
break;
case 1: logixFunction.save();
break;
case 2: logixFunction.saveOffline();
break;
case 3: logixFunction.createOpenLocalPrompt();
closeNavmenu(); // createSaveAsImgPrompt();
break;
case 4: logixFunction.clearProject();
closeNavmenu();
break;
case 5: logixFunction.recoverProject();
closeNavmenu();
break;
case 6: logixFunction.newCircuit();
closeNavmenu();
break;
case 7: logixFunction.newVerilogModule();
closeNavmenu();
break;
case 8: logixFunction.createSubCircuitPrompt();
closeNavmenu();
break;
case 9: logixFunction.createCombinationalAnalysisPrompt();
closeNavmenu();
break;
case 10: logixFunction.bitconverter();
closeNavmenu();
break;
case 11: createSaveAsImgPrompt();
closeNavmenu();
break;
case 12: logixFunction.colorThemes();
closeNavmenu();
break;
case 13: logixFunction.generateVerilog();
closeNavmenu();
break;
case 14: logixFunction.showTourGuide();
closeNavmenu();
break;
case 15: window.open('https://docs.circuitverse.org');
break;
case 16: window.open('https://learn.circuitverse.org');
break;
case 17: window.open('https://circuitverse.org/forum');
break;
default:
closeNavmenu();
break;
}
}
function closeNavmenu() {
navMenuButton[0].style.height = '0';
smallnavbar.classList.remove('active');
}
Source