modal.js

/**
 * @file modal.js
 * @description This file contains every function needed to spawn & populate the popup for the sub-menus.
 * 
 * Functions included in this file : 
 *  - **createSelect**
 *  - **displayBaseModal**
 *  - **hideModal**
 *  - **clearModal**
 *  - **populateModalForMeasure_AUTO**
 *  - **populateModalForSave**
 *  - **populateModalForMeasure_MATHS**
 *  - **populateModalForTrigger**
 *  - **populateModalForCursors**
 *  - **populateModalForSize**
 *  - **populateModalForDisplay**
 *  - **populateModalForSetup**
 * 
 * @version 1.0.0
 * @since 2024-05-31
 * @author Owen Pichot
 * 
 * @license Public Domain
 */

/**
 * @module Modals
 */

/**
 * This function creates an html select input and fills it with the options passed to it.
 * You can then assign the input anywhere within your page.
 * Each option passed to the function must include a 'value' and 'text'.
 * Value will be the value linked to the input when the option is selected.
 * Text will be the text displayed to the user for each option field.
 * 
 * @function createSelect
 * @memberof module:Modals
 * @param {object} options List of options to assign to the input.
 * @returns {object} Returns a DOM input element filled with options.
 * @example
 * const operationOptions = [
 *       {value: "none", text: "None"},
 *       {value: "add", text: "+"},
 *       {value: "sub", text: "-"},
 *       {value: "mult", text: "*"},
 *       {value: "div", text: "/"},
 *       {value: "squared", text: "²"},
 *       {value: "deriv", text: "derivative"},
 *       {value: "integral", text: "integral"},
 *       {value: "fft", text: "FFT"},
 *   ];
 * 
 * createSelect(operationOptions);
 */
function createSelect(options){
    const selectElement = document.createElement("select");
    options.forEach(option => {
        const optionElement = document.createElement('option');
        optionElement.value = option.value;
        optionElement.textContent = option.text;
        selectElement.appendChild(optionElement)
    });
    selectElement.classList.add("modal-select-trigger");
    return selectElement;
};

/**
 * This function displays the 'base modal' on the screen.
 * The base modal is blank by default and needs to be populated.
 * 
 * @function displayBaseModal
 * @memberof module:Modals
 * @returns {void}
 */
function displayBaseModal(){
    MODAL.style.display = "block";

    let modalClose = document.getElementsByClassName("close")[0];


    modalClose.onclick = function() {
        hideModal();
    };

    window.onclick = function(event) {
        if (event.target == MODAL) {
            hideModal();
        }
    };
};

/**
 * This function hides the modal if displayed on screen.
 * 
 * @function hideModal
 * @memberof module:Modals
 * @returns {void}
 */
function hideModal() {
    MODAL.style.display = "none"; // Hide the modal by setting display to 'none'
    clearModal();
};

/**
 * This function deletes every DOM elements within the popup modal including all event listeners and such.
 * 
 * @function clearModal
 * @memberof module:Modals
 * @returns {void}
 */
function clearModal(){
    let modalContentDiv = document.getElementById("modal-generated-content");

    //Here instead of just removing the children of this element, we clone it and replace it with the clone
    //This ensures that the event listeners are also removed.
    let modalClone = modalContentDiv.cloneNode(false);
    modalContentDiv.parentNode.replaceChild(modalClone, modalContentDiv);
};

/**
 * This function populates the base modal for the user to be able to select which auto-measures they wish to display on screen (vpp, rms, etc.).
 * 
 * 
 * @function populateModalForMeasure_AUTO
 * @memberof module:Modals
 * @returns {void}
 * @fires MEASURE This function will fire when the user clicks on the MEASURE button.
 * @listens Measure When a user clicks on a measure to display/hide, the function 'toggleMeasurement' will be fired.
 * @listens Reset 'resetMeasurements' will be called whenever a user clicks on the reset button.
 * @listens Page-Change The modal will switch to the math operations when the user clicks on the 'autoSwitchButton'.
 */
function populateModalForMeasure_AUTO(){
    let modalContentDiv = document.getElementById("modal-generated-content");

    const channelOptions = [];
    Object.keys(channelData).forEach(key => {
        let channelNumber = parseInt(key.substring(2), 10)
        channelOptions.push({value: key, text: "Channel " + channelNumber});
    });

    const measureOptions = [
        {text: "Min", varKey: "min", id: "minButton", onClick: () => { toggleMeasurement('min', "minButton"); }},
        {text: "Max", varKey: "max", id: "maxButton", onClick: () => { toggleMeasurement('max', "maxButton") }},
        {text: "Vpp", varKey: "vpp", id: "vppButton", onClick: () => { toggleMeasurement('vpp', "vppButton") }},
        {text: "Avg", varKey: "mean", id: "avgButton", onClick: () => { toggleMeasurement('mean', "avgButton") }},
        {text: "RMS", varKey: "rms", id: "rmsButton", onClick: () => { toggleMeasurement('rms', "rmsButton") }},
        {text: "F Avg", varKey: "freq", id: "freqButton", onClick: () => { toggleMeasurement('freq', "freqButton") }},
        {text: "High", varKey: "highFreq", id: "highButton", onClick: () => { toggleMeasurement('highFreq', "highButton") }},
        {text: "Low", varKey: "lowFreq", id: "lowButton", onClick: () => { toggleMeasurement('lowFreq', "lowButton") }},
        {text: "Mid", varKey: "mid", id: "midButton", onClick: () => { toggleMeasurement('mid', "midButton") }},
    ];

    const title = document.createElement("h5");
    title.innerHTML = "Auto Measurements";
    modalContentDiv.appendChild(title);

    const container1 = document.createElement("span");

    const label1 = document.createElement("label");
    label1.textContent = "Channel : ";
    container1.appendChild(label1);

    const selectChannel = createSelect(channelOptions);
    selectChannel.id = "selectChannel";
    selectChannel.value = autoMeasureOptions.associatedChannel;
    container1.appendChild(selectChannel);

    selectChannel.addEventListener("change", function(){
        autoMeasureOptions.associatedChannel = selectChannel.value;
    });

    modalContentDiv.appendChild(container1);

    const buttonContainer = document.createElement("span");
    buttonContainer.id = "buttonContainer";

    measureOptions.forEach(option => {
        const button = document.createElement("button");
        button.textContent = option.text;
        button.id = option.id;
        button.classList.add("modal-measure-button");
        button.addEventListener("click", option.onClick);
        buttonContainer.appendChild(button);

        //set the buttons green if this measure is set
        if (autoMeasureOptions[option.varKey].set) {
            button.className = 'modal-measure-button active-measure-button';
        }else{
            button.className = 'modal-measure-button inactive-measure-button';
        }
    });

    modalContentDiv.appendChild(buttonContainer);

    const resetButton = document.createElement("button");
    resetButton.textContent = "RESET";
    resetButton.id = "resetButton";
    resetButton.classList.add("modal-measure-button");

    resetButton.addEventListener("click", function(){
        resetMeasurements();
    });

    const autoSwitchButton = document.createElement("button");
    autoSwitchButton.textContent = "← Math Functions";
    autoSwitchButton.id = "autoSwitchButton";
    autoSwitchButton.classList.add("modal-measure-button");

    autoSwitchButton.addEventListener("click", function(){
        clearModal();
        populateModalForMeasure_MATHS();
    });

    modalContentDiv.appendChild(resetButton);
    modalContentDiv.appendChild(autoSwitchButton);
};

/**
 * This function populates the base modal for the user to be able to choose which type of file they which to save the data under.
 * 
 * @function populateModalForSave
 * @memberof module:Modals
 * @returns {void}
 * @fires SAVE This function will fire when the user clicks on the SAVE button.
 * @listens csvButton Start the function 'downloadDataToCsv' and save the channels' data in a .csv file.
 * @listens pngButton Start the function 'downloadCanvasAsImage' and save the channels' data as a .png picture.
 * @listens jpegButton Start the function 'downloadCanvasAsImage' and save the channels' data as a .jpeg picture.
 * @listens clipBoardButton Start the function 'copyCanvasToClipboard' and save the channels' data as a .png to the clipboard.
 */
function populateModalForSave(){
    let modalContentDiv = document.getElementById("modal-generated-content");

    title = document.createElement("h5");
    csvButton = document.createElement("button");
    pngButton = document.createElement("button");
    jpegButton = document.createElement("button");
    clipBoardButton = document.createElement("button");

    title.innerHTML = "Choose a saving option";

    csvButton.classList.add("modal-save-button");
    pngButton.classList.add("modal-save-button");
    jpegButton.classList.add("modal-save-button");
    clipBoardButton.classList.add("modal-save-button");

    csvButton.innerHTML = "Save as CSV";
    pngButton.innerHTML = "Save as PNG";
    jpegButton.innerHTML = "Save as JPEG";
    clipBoardButton.innerHTML = "Copy to clipboard";

    modalContentDiv.appendChild(title);
    modalContentDiv.appendChild(csvButton);
    modalContentDiv.appendChild(pngButton);
    modalContentDiv.appendChild(jpegButton);
    modalContentDiv.appendChild(clipBoardButton);


    csvButton.addEventListener("click", downloadDataToCsv);
    pngButton.addEventListener("click", function(){downloadCanvasAsImage("png")});
    jpegButton.addEventListener("click", function(){downloadCanvasAsImage("jpeg")});
    clipBoardButton.addEventListener("click", copyCanvasToClipboard);
};

/**
 * This function populates the base modal for the user to be able to generate new signals.
 * On this screen, the user can use math operations (+, -, fft, sqrd, etc.) to generate new signals from pre-existing ones.
 * 
 * @function populateModalForMeasure_MATHS
 * @memberof module:Modals
 * @returns {void}
 * @listens Page-Change The modal will switch to auto-measures when the user clicks on the 'autoSwitchButton'.
 * @listens saveButton Start the logic required to create a new signal when the user clicks it.
 */
function populateModalForMeasure_MATHS(){
    let modalContentDiv = document.getElementById("modal-generated-content");

    const emptySlotOptions = [];
    for (let i = 1; i < 11; i++){
        if (channelData["CH" + i] == undefined){//this condition is to avoid overwriting a maths channel that is already in use
            emptySlotOptions.push({value: "CH" + i, text: "Channel " + i});
        }; 
    }

    const channelOptions = [];
    Object.keys(channelData).forEach(key => {
        channelOptions.push({value: key, text: key});
    });

    const operationOptions = [
        {value: "none", text: "None"},
        {value: "add", text: "+"},
        {value: "sub", text: "-"},
        {value: "mult", text: "*"},
        {value: "div", text: "/"},
        {value: "squared", text: "²"},
        {value: "deriv", text: "derivative"},
        {value: "integral", text: "integral"},
        {value: "fft", text: "FFT"},
    ];

    const title = document.createElement("h5");
    title.innerHTML = "Math functions";
    modalContentDiv.appendChild(title);

    const container1 = document.createElement("span");

    const label1 = document.createElement("label");
    label1.textContent = "Channel slot : ";
    container1.appendChild(label1);

    const selectSlotChannel = createSelect(emptySlotOptions);
    selectSlotChannel.id = "selectSlotChannel";
    container1.appendChild(selectSlotChannel);

    modalContentDiv.appendChild(container1);
    const container2 = document.createElement("span");

    const label2 = document.createElement("label");
    label2.textContent = "Channel : ";
    container2.appendChild(label2);

    const selectChannel = createSelect(channelOptions);
    selectChannel.id = "selectChannel";
    container2.appendChild(selectChannel);

    modalContentDiv.appendChild(container2);
    const container3 = document.createElement("span");

    const label3 = document.createElement("label");
    label3.textContent = "Operation : ";
    container3.appendChild(label3);

    const selectOperation = createSelect(operationOptions);
    selectOperation.id = "selectOperation";
    container3.appendChild(selectOperation);

    modalContentDiv.appendChild(container3);

    const container4 = document.createElement("span");

    const label4 = document.createElement("label");
    label4.textContent = "Channel 2 : ";
    container4.appendChild(label4);

    const selectSecondChannel = createSelect(channelOptions);
    selectSecondChannel.id = "selectSecondChannel";
    selectSecondChannel.value = "none";
    container4.style.display = "none";//hidden by default until user chooses an operation requiring a 2nd channel
    container4.appendChild(selectSecondChannel);

    modalContentDiv.appendChild(container4);

    selectOperation.addEventListener("change", function(){
        const value = selectOperation.value;
        if (value == "add" || value == "sub" || value == "mult" || value == "div"){
            container4.style.display = "block";
        }else{
            container4.style.display = "none";
        }
    });

    const saveButton = document.createElement("button");
    saveButton.textContent = "SAVE";
    saveButton.id = "saveButton";
    saveButton.classList.add("modal-measure-button");

    const autoSwitchButton = document.createElement("button");
    autoSwitchButton.textContent = "Auto-Measures →";
    autoSwitchButton.id = "autoSwitchButton";
    autoSwitchButton.classList.add("modal-measure-button");

    //function to check wether we can indeed generate the math signal
    //and then include it in a channel object
    saveButton.addEventListener("click", function(){
        let slotChannel = selectSlotChannel.value;
        let channel1 = selectChannel.value;
        let channel2 = selectSecondChannel.value;
        let operation = selectOperation.value;

        if (operation == "none"){
            showToast("Please select an operation", "toast-error");
        }else{
            if (channel1 == channel2){
                if (operation == "add" || operation == "sub" || operation == "mult" || operation == "div"){
                    showToast("Please select two different channels", "toast-error");
                }else{
                    updateGeneratedMathSignalsData(slotChannel, channel1, channel2, operation);
                    clearModal();
                    populateModalForMeasure_MATHS();
                }
            }else{
                updateGeneratedMathSignalsData(slotChannel, channel1, channel2, operation);
                clearModal();
                populateModalForMeasure_MATHS();
            }
        };
    });
    
    //this section is to display the currently generated math signals
    //and offer the opportunity to the user delete one if he wants to
    const generatedSignalsDiv = document.createElement("div");

    const generatedSignals = []
    Object.keys(channelData).forEach(key => {
        if (channelData[key].type == "generatedData"){
            generatedSignals.push(key);
        }
    });

    if (generatedSignals.length != 0){
        const generatedSignalsTitle = document.createElement("h6");
        generatedSignalsTitle.textContent = "Maths Channels in-use : ";
        generatedSignalsDiv.appendChild(generatedSignalsTitle);

        generatedSignals.forEach(signal => {
            const signalSpan = document.createElement("span");
            const signalText = document.createElement("p");
            const deleteButton = document.createElement("button");

            signalSpan.classList.add("generated-signal");
            signalText.textContent = signal + " → ";
            // deleteButton.textContent = "X";
            deleteButton.classList.add("delete-button");

            signalSpan.appendChild(signalText);
            signalSpan.appendChild(deleteButton);
            generatedSignalsDiv.appendChild(signalSpan);

            deleteButton.addEventListener("click", function(){
                delete channelData[signal];
                signalSpan.remove();

                channelButton = document.getElementById(signal);

                channelButton.className = "channel-not-displayed";
                config.numChannels -= 1;

                //Here we also get rid of the cursor associated to the signal.
                const scroller = document.getElementById("scroller-" + signal);
                scroller.style.display = "none";

                clearModal();
                populateModalForMeasure_MATHS();
            });
        });
    };

    autoSwitchButton.addEventListener("click", function(){
        console.log("switch to auto-measurements")
        clearModal();
        populateModalForMeasure_AUTO();
    });

    modalContentDiv.appendChild(saveButton);
    if (generatedSignals.length != 0){modalContentDiv.appendChild(generatedSignalsDiv);};
    modalContentDiv.appendChild(autoSwitchButton);
};

/**
 * This function populates the base modal to select the trigger related options.
 * 
 * @function populateModalForTrigger
 * @memberof module:Modals
 * @returns {void}
 * @listens button Clicking on the button will save the selected settings.
 * @fires TRIGGER This function will fire when the user clicks on the TRIGGER button.
 */
function populateModalForTrigger(){
    // console.log("Trigger settings : ", triggerOptions);
    let modalContentDiv = document.getElementById("modal-generated-content");

    const triggerOnOffOptions = [
        {value: "off", text: "Off"},
        {value: "on", text: "On"},
    ]

    const triggerModeOptions = [
        {value: "edge", text: "Edge-Trigger"},
        {value: "window", text: "Window-Trigger"},
    ]

    const triggerChannelOptions = [];
    Object.keys(channelData).forEach(key => {
        let channelNumber = parseInt(key.substring(2), 10)
        triggerChannelOptions.push({value: key, text: "Channel " + channelNumber});
    });

    const triggerSlopeOptions = [
        {value: "both", text: "Both"},
        {value: "rising", text: "Rising"},
        {value: "falling", text: "Falling"},
    ]

    const title = document.createElement("h5");
    title.innerHTML = "Trigger options";
    modalContentDiv.appendChild(title);

    const label1 = document.createElement("label"); //Trigger on/off
    label1.textContent = "Trigger on/off";
    modalContentDiv.appendChild(label1);

    const selectOnOffStatus = createSelect(triggerOnOffOptions);
    selectOnOffStatus.id = "selectOnOffStatus";
    selectOnOffStatus.value = triggerOptions.isTriggerOn;
    modalContentDiv.appendChild(selectOnOffStatus);

    const label2 = document.createElement("label"); //Trigger mode
    label2.textContent = "Trigger mode";
    modalContentDiv.appendChild(label2);

    const selectTriggerMode = createSelect(triggerModeOptions);
    selectTriggerMode.id = "selectTriggerMode";
    selectTriggerMode.value = triggerOptions.triggerMode;
    modalContentDiv.appendChild(selectTriggerMode);

    const label3 = document.createElement("label"); //Trigger channel
    label3.textContent = "Trigger channel";
    modalContentDiv.appendChild(label3);

    const selectTriggerChannel = createSelect(triggerChannelOptions);
    selectTriggerChannel.id = "selectTriggerChannel";
    selectTriggerChannel.value = triggerOptions.triggerChannel;
    modalContentDiv.appendChild(selectTriggerChannel);

    const label4 = document.createElement("label"); //Trigger slope
    label4.textContent = "Trigger slope";
    modalContentDiv.appendChild(label4);

    const selectTriggerSlope = createSelect(triggerSlopeOptions);
    selectTriggerSlope.id = "selectTriggerSlope";
    selectTriggerSlope.value = triggerOptions.triggerSlope;
    modalContentDiv.appendChild(selectTriggerSlope);


    const label5 = document.createElement("label"); //Trigger level
    label5.textContent = "Trigger level (mV)";
    modalContentDiv.appendChild(label5);

    const TriggerLevelInput = document.createElement("input");
    TriggerLevelInput.type = "number";
    TriggerLevelInput.min = -(config.voltage / 2) * 1000;
    TriggerLevelInput.max = (config.voltage / 2) * 1000;
    TriggerLevelInput.value = triggerOptions.triggerLevel;
    TriggerLevelInput.classList.add("modal-select-trigger");
    TriggerLevelInput.id = "TriggerLevelInput";
    modalContentDiv.appendChild(TriggerLevelInput);

    const label6 = document.createElement("label"); //Window level min
    label6.textContent = "Window level min (mV)";
    modalContentDiv.appendChild(label6);

    const WindowLevelMinInput = document.createElement("input");
    WindowLevelMinInput.type = "number";
    WindowLevelMinInput.min = -(config.voltage / 2) * 1000;
    WindowLevelMinInput.max = (config.voltage / 2) * 1000;
    WindowLevelMinInput.value = triggerOptions.windowLevelMin;
    WindowLevelMinInput.classList.add("modal-select-trigger");
    WindowLevelMinInput.id = "WindowLevelMinInput";
    modalContentDiv.appendChild(WindowLevelMinInput);

    const label7 = document.createElement("label"); //Window level max
    label7.textContent = "Window level max (mV)";
    modalContentDiv.appendChild(label7);

    const WindowLevelMaxInput = document.createElement("input");
    WindowLevelMaxInput.type = "number";
    WindowLevelMaxInput.min = -(config.voltage / 2) * 1000;
    WindowLevelMaxInput.max = (config.voltage / 2) * 1000;
    WindowLevelMaxInput.value = triggerOptions.windowLevelMax;
    WindowLevelMaxInput.classList.add("modal-select-trigger");
    WindowLevelMaxInput.id = "WindowLevelMaxInput";
    modalContentDiv.appendChild(WindowLevelMaxInput);

    if (triggerOptions.triggerMode == "edge"){
        WindowLevelMinInput.disabled = true;
        WindowLevelMaxInput.disabled = true;
        TriggerLevelInput.disabled = false;
    }else{
        WindowLevelMinInput.disabled = false;
        WindowLevelMaxInput.disabled = false;
        TriggerLevelInput.disabled = true;
    }

    selectTriggerMode.addEventListener("change", function(){
        console.log("Trigger mode changed to : ", selectTriggerMode.value);
        if (selectTriggerMode.value === "edge"){
            WindowLevelMinInput.disabled = true;
            WindowLevelMaxInput.disabled = true;
            TriggerLevelInput.disabled = false;
        } else if (selectTriggerMode.value === "window"){
            WindowLevelMinInput.disabled = false;
            WindowLevelMaxInput.disabled = false;
            TriggerLevelInput.disabled = true;
        }
    });

    const label8 = document.createElement("label"); //Hold off
    label8.textContent = "Hold off (s)";
    modalContentDiv.appendChild(label8);

    const holdOffInput = document.createElement("input");
    holdOffInput.type = "number";
    holdOffInput.min = 0;
    holdOffInput.max = 3600;
    holdOffInput.value = triggerOptions.holdOff;
    holdOffInput.classList.add("modal-select-trigger");
    holdOffInput.id = "holdOffInput";
    modalContentDiv.appendChild(holdOffInput);

    const button = document.createElement("button");// SAVE CHANGES
    button.textContent = "Apply Trigger Settings";
    button.classList.add("modal-trigger-button");
    button.id = "triggerOptionsSaveButton";
    modalContentDiv.appendChild(button);

    button.addEventListener("click", function(){
        updateTriggerSettings(modalContentDiv);
        hideModal();
    });
};

/**
 * This function populates the base modal to select which measure cursors to display and the style of the information display.
 * It's important to note that this function does not call any other function to display the cursors, 
 * these will display automatically whenever cursorOptions.isVerticalCursorOn or cursorOptions.isHorizontalCursorOn are set to true.
 * 
 * @function populateModalForCursors
 * @memberof module:Modals
 * @returns {void}
 * @listens resetButton Clicking on the reset button will remove all cursors currently displayed on screen.
 * @fires CURSORS This function will fire when the user clicks on the CURSORS button.
 */
function populateModalForCursors(){
    let modalContentDiv = document.getElementById("modal-generated-content");

    const horizontalOptions = [
        {text: "On", value: "true"},
        {text: "Off", value: "false"}
    ];

    const verticalOptions = [
        {text: "On", value: "true"},
        {text: "Off", value: "false"}
    ];

    const valueOptions = [
        {text: "On cursor", value: "oncursor"},
        {text: "In display", value: "indisplay"}
    ];

    const title = document.createElement("h5");
    title.innerHTML = "Cursor Options";
    modalContentDiv.appendChild(title);

    const container1 = document.createElement("span");

    const label1 = document.createElement("label");
    label1.textContent = "Horizontal : ";
    container1.appendChild(label1);

    const selectHorizontal = createSelect(horizontalOptions);
    selectHorizontal.id = "selectHorizontal";
    selectHorizontal.value = cursorOptions.isHorizontalCursorOn;
    container1.appendChild(selectHorizontal);

    selectHorizontal.addEventListener("change", function(){
        cursorOptions.isHorizontalCursorOn = this.value;
        toggleDisplayForHorizontalCursorScrollers();
    });

    modalContentDiv.appendChild(container1);
    const container2 = document.createElement("span");

    const label2 = document.createElement("label");
    label2.textContent = "Vertical : ";
    container2.appendChild(label2);

    const selectVertical = createSelect(verticalOptions);
    selectVertical.id = "selectVertical";
    selectVertical.value = cursorOptions.isVerticalCursorOn;
    container2.appendChild(selectVertical);

    selectVertical.addEventListener("change", function(){
        cursorOptions.isVerticalCursorOn = this.value;
        toggleDisplayForVerticalCursorScrollers();
    });

    modalContentDiv.appendChild(container2);
    const container3 = document.createElement("span");

    const label3 = document.createElement("label");
    label3.textContent = "Value : ";
    container3.appendChild(label3);

    const selectValue = createSelect(valueOptions);
    selectValue.id = "selectValue";
    selectValue.value = cursorOptions.cursorsValueDisplay;
    container3.appendChild(selectValue);

    selectValue.addEventListener("change", function(){
        cursorOptions.cursorsValueDisplay = this.value;
    });

    modalContentDiv.appendChild(container3);

    const resetButton = document.createElement("button");
    resetButton.textContent = "Reset Cursors";
    resetButton.id = "resetButton";
    resetButton.classList.add("modal-measure-button");

    modalContentDiv.appendChild(resetButton);

    resetButton.addEventListener("click", function(){
        console.log("Reset the cursors.");
        cursorOptions.isVerticalCursorOn = "false";
        cursorOptions.isHorizontalCursorOn = "false";
        cursorOptions.cursorsValueDisplay = "oncursor";
        cursorOptions.horizontalAPosition = 266;
        cursorOptions.horizontalBPosition = 533;
        cursorOptions.verticalAPosition = 400;
        cursorOptions.verticalBPosition = 800;
        selectHorizontal.value = "false";
        selectVertical.value = "false";
        selectValue.value = "oncursor";
        document.getElementById("vertical-scroller-A").style.display = "none";
        document.getElementById("vertical-scroller-B").style.display = "none";
        document.getElementById("scroller-horizontal-A").style.display = "none";
        document.getElementById("scroller-horizontal-B").style.display = "none";
    });
};

/**
 * This function populates the base modal to allow the user to change the current screen size of the oscilloscope.
 * The default value for the maximized display is "TD" because we can't prepare for every screen size available on the market.
 * 
 * @function populateModalForSize
 * @memberof module:Modals
 * @returns {void}
 * @listens changeScreenSize Whenever the input is changed by the user.
 * @fires SIZE This function will fire when the user clicks on the SIZE button.
 */
function populateModalForSize(){
    let modalContentDiv = document.getElementById("modal-generated-content");

    const sizeOptions = [
        {text: "Tiny", value: "400|267"},
        {text: "Small", value: "800|533"},
        {text: "Standard", value: "1200|800"},
        {text: "Large", value: "1400|900"},
        {text: "Maximized", value: "TD"},//determine current window size and apply canvas to that size
    ];

    const title = document.createElement("h5");
    title.innerHTML = "Screen size";
    modalContentDiv.appendChild(title);

    const selectSize = createSelect(sizeOptions);
    selectSize.id = "sizeSelectionInput";
    if (CANVAS.width == 400){
        selectSize.value = "400|267";
    }else if (CANVAS.width == 800){
        selectSize.value = "800|533";
    }else if (CANVAS.width == 1200){
        selectSize.value = "1200|800";
    }else if (CANVAS.width == 1400){
        selectSize.value = "1400|900";
    }else{
        selectSize.value = "TD";
    }
    modalContentDiv.appendChild(selectSize);

    selectSize.addEventListener("change", function(){
        changeScreenSize(selectSize.value);
    });
};

/**
 * This function populates the base modal to allow the user to :
 *  - Unzoom the screen.
 *  - Choose to display or not the grid.
 *  - Choose which theme to use (light / dark).
 * 
 * @function populateModalForDisplay
 * @memberof module:Modals
 * @returns {void}
 * @listens unzoomButton When clicked, the function 'resetZoom' will be called if the screen is currently zoomed-in.
 * @listens selectGridDisplay When changed, the variable 'config.gridDisplay' will be set to 1 or 0 depending on the user's choice.
 * @listens selectTheme When changed, the variable 'config.theme' will be set to either 'light' or 'dark' depending on the user's choice.
 * @fires DISPLAY This function will fire when the user clicks on the DISPLAY button.
 */
function populateModalForDisplay(){
    let modalContentDiv = document.getElementById("modal-generated-content");

    const title = document.createElement("h5");
    title.innerHTML = "Display options";
    modalContentDiv.appendChild(title);

    const unzoomButton = document.createElement("button");
    unzoomButton.textContent = "Unzoom";
    unzoomButton.id = "unzoomButton";
    unzoomButton.classList.add("modal-measure-button");

    unzoomButton.addEventListener("click", function(){
        if (zoomConfig.isZoomed){
            resetZoom();
            showToast("Zoom reset", "toast-info");
        }else{
            showToast("No zoom to reset", "toast-error");
        }
    });

    modalContentDiv.appendChild(unzoomButton);

    const gridOptions = [
        {text: "On", value: 1},
        {text: "Off", value: 0}, 
    ]

    const container1 = document.createElement("span");

    const label2 = document.createElement("label");
    label2.textContent = "Grid Display : ";
    container1.appendChild(label2);

    const selectGridDisplay = createSelect(gridOptions);
    selectGridDisplay.id = "selectGridDisplay";
    selectGridDisplay.value = config.gridDisplay;
    
    container1.appendChild(selectGridDisplay);
    modalContentDiv.appendChild(container1);

    selectGridDisplay.addEventListener("change", function(){
        if (selectGridDisplay.value == 1){
            config.gridDisplay = 1;
            showToast("Grid displayed", "toast-info");
            if (!isRunning){
                drawGrid('rgba(128, 128, 128, 0.5)', 3);
            };
        }else{
            config.gridDisplay = 0;
            showToast("Grid Removed", "toast-info");
            if (!isRunning){
                clearCanvas();
            };
        }
    });

    const lightModeOptions = [
        {text: "Light", value: "light"},
        {text: "Dark", value: "dark"},
    ];

    const container2 = document.createElement("span");

    const label3 = document.createElement("label");
    label3.textContent = "Theme : ";
    container2.appendChild(label3);

    const selectTheme = createSelect(lightModeOptions);
    selectTheme.id = "selectTheme";
    selectTheme.value = config.theme;

    container2.appendChild(selectTheme);
    modalContentDiv.appendChild(container2);

    selectTheme.addEventListener("change", function(){changeScreenLightMode(selectTheme.value)});
};

/**
 * This function populates the base modal for the setup sub-menu.
 * It allows the user to select each channel's color both in dark and light mode.
 * They can also change the grid's opacity from here.
 * This function does not save the user's selections to the database, for this, the function 'saveColorChoices' is called.
 * 
 * @function populateModalForSetup
 * @memberof module:Modals
 * @returns {void}
 * @fires SETUP This function will fire when the user clicks on the SETUP button.
 * @listens saveButton When clicked, the styles set by the user will be updated.
 */
function populateModalForSetup(){
    let modalContentDiv = document.getElementById("modal-generated-content");

    const colorOptionsLight = [
        //We have to display the color's name because some browsers (firefox) do not display the colors of "option" elements.
        {text: "Green", value: "green"},
        {text: "Red", value: "red"},
        {text: "Gray", value: "gray"},
        {text: "Olive", value: "olive"},
        {text: "Cyan", value: "cyan"},
        {text: "Orange", value: "orange"},
        {text: "Maroon", value: "maroon"},
        {text: "Blue", value: "blue"},
        {text: "Purple", value: "purple"},
        {text: "Black", value: "black"},
    ];

    const colorOptionsDark = [
        {text: "Lime", value: "lime"},
        {text: "Red", value: "red"},
        {text: "Cyan", value: "cyan"},
        {text: "Yellow", value: "yellow"},
        {text: "Green", value: "green"},
        {text: "Orange", value: "orange"},
        {text: "Pink", value: "pink"},
        {text: "Blue", value: "blue"},
        {text: "Fuchsia", value: "fuchsia"},
        {text: "White", value: "white"},
    ];

    const title = document.createElement("h4");
    title.textContent = "Setup Options";
    modalContentDiv.appendChild(title);

    const container1 = document.createElement("div");
    container1.id = "colorSelectionContainer";

    const container2 = document.createElement("div");
    container2.id = "DarkColorSelectionContainer";

    const container3 = document.createElement("div");
    container3.id = "LightColorSelectionContainer";

    const subTitle1 = document.createElement("h5");
    subTitle1.textContent = "Dark";
    const subTitle2 = document.createElement("h5");
    subTitle2.textContent = "Light";

    container1.appendChild(container2);
    container1.appendChild(container3)
    container2.appendChild(subTitle1);
    container3.appendChild(subTitle2);

    for (let i = 1; i < 11; i++){//Dark mode color options
        const individualChannelColorContainer = document.createElement("span");
        individualChannelColorContainer.classList.add("individualChannelColorContainer");
        const para = document.createElement("p");
        para.textContent = "CH" + i;
        const colorSelect = createSelect(colorOptionsDark);
        colorSelect.id = "channelColorD-"+i;

        colorSelect.style.backgroundColor = channelsMetaData["CH"+i].colorDark;
        colorSelect.value = channelsMetaData["CH"+i].colorDark;

        colorSelect.addEventListener("change", function(){
            colorSelect.style.backgroundColor = colorSelect.value;
        });

        //These 3 lines below display the color associated with each option element
        //It does not work on certain browser (firefox)
        colorSelect.childNodes.forEach((option, index) => {
            option.style.backgroundColor = colorOptionsDark[index].value;
        });

        individualChannelColorContainer.appendChild(para);
        individualChannelColorContainer.appendChild(colorSelect);
        container2.appendChild(individualChannelColorContainer);
    };

    for (let i = 1; i < 11; i++){//Light mode color options
        const individualChannelColorContainer = document.createElement("span");
        individualChannelColorContainer.classList.add("individualChannelColorContainer");
        const para = document.createElement("p");
        para.textContent = "CH" + i;
        const colorSelect = createSelect(colorOptionsLight);
        colorSelect.id = "channelColorL-"+i;

        colorSelect.style.backgroundColor = channelsMetaData["CH"+i].colorLight;
        colorSelect.value = channelsMetaData["CH"+i].colorLight;

        colorSelect.addEventListener("change", function(){
            colorSelect.style.backgroundColor = colorSelect.value;
        });

        //These 3 lines below display the color associated with each option element
        //It does not work on certain browser (firefox)
        colorSelect.childNodes.forEach((option, index) => {
            option.style.backgroundColor = colorOptionsLight[index].value;
        });

        individualChannelColorContainer.appendChild(para);
        individualChannelColorContainer.appendChild(colorSelect);
        container3.appendChild(individualChannelColorContainer);
    };

    modalContentDiv.appendChild(container1);

    const container4 = document.createElement("div");
    container4.id = "GridOpacityContainer";

    const label = document.createElement("label");
    label.textContent = "Grid Opacity (0-1) : ";
    const gridOpacityInput = document.createElement("input");
    gridOpacityInput.id = "gridOpacityInput";
    gridOpacityInput.type = "number"
    gridOpacityInput.min = 0;
    gridOpacityInput.max = 1;
    gridOpacityInput.step = 0.1;
    gridOpacityInput.value = config.gridOpacity;

    container4.appendChild(label);
    container4.appendChild(gridOpacityInput);

    modalContentDiv.appendChild(container4);

    const saveButton = document.createElement("button");
    saveButton.textContent = "SAVE";
    saveButton.id = "setupModalSaveButton"
    saveButton.addEventListener("click", saveColorChoices);

    modalContentDiv.appendChild(saveButton);
};