Initial commit

This commit is contained in:
2018-10-23 23:05:39 +01:00
commit 89ff6fec6f
32 changed files with 22283 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
import pathops
import os
from matrix_test.generate_matrix_stimulus import generateStimulus
import time
import config
'''
Module containing functions to be processed asynchronously
'''
def generate_matrix_stimulus(obj_response, n_part, snr_len, snr_num, mat_dir, save_dir):
#from celery.contrib import rdb
#rdb.set_trace()
n_part = int(n_part)
for participant_n in range(n_part):
obj_response.attr('#progress-bar', 'style','width={}'.format((participant_n+1/n_part)*100.))
time.sleep(1)
return None
'''
save_dir = os.path.join(save_dir)
mat_dir = os.path.join(mat_dir)
pathops.dir_must_exist(save_dir)
pathops.dir_must_exist(mat_dir)
n_part = int(n_part)
snr_len = float(snr_len)
snr_num = int(snr_num)
for participant_n in range(n_part):
obj_response.attr('#progress-bar', 'style','width={}'.format((participant_n+1/n_part)*100.))
genLength = (snr_len * snr_num) * 60.
partDir = os.path.join(save_dir, "Partcipant{0:02d}".format(participant_n))
pathops.dir_must_exist(partDir)
filenames = generateStimulus(mat_dir, genLength, partDir)
return {'current': n_part, 'total': n_part, 'status': 'Task completed!',
'result': 42}
'''
+11
View File
@@ -0,0 +1,11 @@
from flask import Flask
from flask_socketio import SocketIO, emit
import os
gui_dir = os.path.join(os.getcwd(), "gui") # development path
if not os.path.exists(gui_dir): # frozen executable path
gui_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gui")
server = Flask(__name__)
server.config["SEND_FILE_MAX_AGE_DEFAULT"] = 1 # disable caching
socketio = SocketIO(async_mode='threading')
Executable
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from threading import Thread, Lock
import logging
import webview
from time import sleep
from server import run_server
server_lock = Lock()
logger = logging.getLogger(__name__)
def url_ok(url, port):
# Use httplib on Python 2
try:
from http.client import HTTPConnection
except ImportError:
from httplib import HTTPConnection
try:
conn = HTTPConnection(url, port)
conn.request("GET", "/")
r = conn.getresponse()
return r.status == 200
except:
logger.exception("Server not started")
return False
if __name__ == '__main__':
logger.debug("Starting server")
# Run server in seperate thread
t = Thread(target=run_server)
t.daemon = True
t.start()
logger.debug("Checking server")
# Check server is up and running
while not url_ok("127.0.0.1", 23948):
sleep(0.1)
logger.debug("Server started")
# Create browser window for user interaction with GUI
webview.create_window("BPLabs",
"http://127.0.0.1:23948/home",
width=1000, height=700, min_size=(1000, 500), debug=True)
+63
View File
@@ -0,0 +1,63 @@
import os
import shutil
from six import string_types
def get_filename(path):
"""
Returns the filename without extension from path provided
"""
return os.path.splitext(os.path.basename(path))[0]
def file_must_exist(path):
"""
Checks that the path specified exists
If not or the path is a directory then raises and IOError
"""
# Check that path is a string value
if not isinstance(path, string_types):
raise TypeError("File path argument is not a string")
if not os.path.isfile(path):
raise IOError("File doesn't exist: ", path)
else:
return True
def dir_must_exist(path):
"""
Checks that the directory exists.
If not then tries to create the directory.
If this fails then an IOError is raised.
"""
if not isinstance(path, string_types):
raise TypeError("Directory path argument is not a string")
try:
os.makedirs(path)
except OSError:
if not os.path.isdir(path):
raise IOError("Directory can't be created: ", path)
return path
def listdir_nohidden(path):
"""
List all files and subdirectories of a directory that aren't hidden.
"""
dir_must_exist(path)
return [os.path.join(path, i) for i in os.listdir(path) if not i.startswith('.')]
def delete_if_exists(path):
"""
Trys to delete the file at the path specified if it exists.
Returns True on succesful deletion else returns False.
Either way there won't be a file at that location after running.
"""
try:
if os.path.isdir(path):
shutil.rmtree(path)
else:
os.remove(path)
except OSError:
return False
return True
+5
View File
@@ -0,0 +1,5 @@
Flask_SocketIO==3.0.2
Flask==1.0.2
six==1.10.0
pywebview==2.1
webview==0.1.5
Executable
+159
View File
@@ -0,0 +1,159 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
from flask import Flask, url_for, render_template, jsonify, request, make_response, g
from flask_socketio import emit
import webview
import webbrowser
import app
import time
from threading import Thread, Event
import config
server = config.server
socketio = config.socketio
@server.after_request
def add_header(response):
# Disable caching? unsure why...
response.headers['Cache-Control'] = 'no-store'
return response
@server.route("/")
def landing():
"""
Render index.html
"""
return render_template("index.html")
@server.route("/choose/path")
def choose_path():
"""
Invokes a folder selection dialog
"""
dirs = webview.create_file_dialog(webview.FOLDER_DIALOG)
if dirs and len(dirs) > 0:
directory = dirs[0]
if isinstance(directory, bytes):
directory = directory.decode("utf-8")
response = {"status": "ok", "directory": directory}
else:
response = {"status": "cancel"}
return jsonify(response)
@server.route("/fullscreen")
def fullscreen():
webview.toggle_fullscreen()
return jsonify({})
@server.route('/home')
def homepage():
title = "Welcome"
paragraph = [
"This web app was developed for the generation of stimulus and "
"running of experiments for the PhD project \"Predicting speech "
"in noise performance using evoked responses\".",
"Use the drop down menus to access the various modules of this app."
]
try:
return render_template("home.html", title = title, paragraph=paragraph)
except Exception as e:
return str(e)
@server.route('/mat_dec_stim')
def matDecStim():
return render_template("matrix_decode_stim.html")
thread = Thread()
thread_stop_event = Event()
class StimGenThread(Thread):
'''
Thread object for asynchronous processing of data in Python without locking
up the GUI
'''
def __init__(self):
super(StimGenThread, self).__init__()
def process_stimulus(self):
'''
An example process
'''
for participant_n in range(15):
percent = ((participant_n+1) / 15)*100.
# Emit a message to update the progress bar during execution of the
# python process (see relevant javascript code in
# matrix_decode_stim.html)
socketio.emit('update-progress', {'data': '{}%'.format(percent)}, namespace='/main')
time.sleep(1)
def run(self):
'''
This function is called when the thread starts
'''
self.process_stimulus()
socketio.emit('processing-complete', {'data': ''}, namespace='/main')
@socketio.on('run_mat_stim_gen', namespace='/main')
def generateStim(msg):
'''
When process buton is clicked in GUI, start an asynchronous thread to run
process
'''
thread = StimGenThread()
thread.start()
@socketio.on('open_save_dialog', namespace='/main')
def openSaveDialog():
# Open a file dialog interface for selecting a directory
dirs = webview.create_file_dialog(webview.FOLDER_DIALOG)
if dirs and len(dirs) > 0:
directory = dirs[0]
if isinstance(directory, bytes):
directory = directory.decode("utf-8")
# TODO: Add filepath checking here...
# Send message with selected directory to the GUI
socketio.emit('save-dialog-resp', {'data': directory}, namespace='/main')
@socketio.on('open_mat_dialog', namespace='/main')
def openMatDialog():
# Open a file dialog interface for selecting a directory
dirs = webview.create_file_dialog(webview.FOLDER_DIALOG)
if dirs and len(dirs) > 0:
directory = dirs[0]
if isinstance(directory, bytes):
directory = directory.decode("utf-8")
# TODO: Add filepath checking here...
# Send message with selected directory to the GUI
socketio.emit('mat-dialog-resp', {'data': directory}, namespace='/main')
@server.route('/click_stim')
def clickStim():
return render_template("click_stim.html")
@server.route('/da_stim')
def daStim():
return render_template("da_stim.html")
def run_server():
'''
Start the Flask server
'''
# SocketIO objects are defined in config.py
socketio.init_app(server)
socketio.run(server, host="127.0.0.1", port=23948)
if __name__ == "__main__":
run_server()
+1912
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+7
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+331
View File
@@ -0,0 +1,331 @@
/*!
* Bootstrap Reboot v4.1.3 (https://getbootstrap.com/)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@-ms-viewport {
width: device-width;
}
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #212529;
text-align: left;
background-color: #fff;
}
[tabindex="-1"]:focus {
outline: 0 !important;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 0.5rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: .5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
dfn {
font-style: italic;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}
a {
color: #007bff;
text-decoration: none;
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
a:hover {
color: #0056b3;
text-decoration: underline;
}
a:not([href]):not([tabindex]) {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus {
outline: 0;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
}
pre {
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
-ms-overflow-style: scrollbar;
}
figure {
margin: 0 0 1rem;
}
img {
vertical-align: middle;
border-style: none;
}
svg {
overflow: hidden;
vertical-align: middle;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
color: #6c757d;
text-align: left;
caption-side: bottom;
}
th {
text-align: inherit;
}
label {
display: inline-block;
margin-bottom: 0.5rem;
}
button {
border-radius: 0;
}
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-webkit-appearance: listbox;
}
textarea {
overflow: auto;
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
display: block;
width: 100%;
max-width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
color: inherit;
white-space: normal;
}
progress {
vertical-align: baseline;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
summary {
display: list-item;
cursor: pointer;
}
template {
display: none;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */
File diff suppressed because one or more lines are too long
+8
View File
@@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v4.1.3 (https://getbootstrap.com/)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
File diff suppressed because one or more lines are too long
+6461
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+9030
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+3944
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+7
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+7
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+11
View File
@@ -0,0 +1,11 @@
{% extends 'index.html' %}
{% block content %}
<div class="card">
<div class="card-body">
<h1>{{ title }}</h1>
{% for p in paragraph %}
<p>{{ p }}</p>
{% endfor %}
</div>
</div>
{% endblock %}
+11
View File
@@ -0,0 +1,11 @@
{% extends 'index.html' %}
{% block content %}
<div class="card">
<div class="card-body">
<h1>{{ title }}</h1>
{% for p in paragraph %}
<p>{{ p }}</p>
{% endfor %}
</div>
</div>
{% endblock %}
+8
View File
@@ -0,0 +1,8 @@
{% extends 'index.html' %}
{% block content %}
<div class="card">
<div class="card-body">
Processing complete!
</div>
</div>
{% endblock %}
+11
View File
@@ -0,0 +1,11 @@
{% extends 'index.html' %}
{% block content %}
<div class="card">
<div class="card-body">
<h1>{{ title }}</h1>
{% for p in paragraph %}
<p>{{ p }}</p>
{% endfor %}
</div>
</div>
{% endblock %}
+102
View File
@@ -0,0 +1,102 @@
<html>
<link rel="stylesheet" media="screen" href = "{{ url_for('static', filename='bootstrap.min.css') }}">
<meta name="viewport" content = "width=device-width, initial-scale=1.0">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script type="text/javascript" src = "/static/bootstrap.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
</head>
<body class = "body">
<nav id="main-nav" class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">BPLabs v0.1</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="Home">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Stimulus generation
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="mat_dec_stim">Matrix decoder stimulus</a>
<a class="dropdown-item" href="click_Stim">Click stimulus</a>
<a class="dropdown-item" href="da_stim">/da/ stimulus</a>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Experiment procedure
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">PTA</a>
<a class="dropdown-item" href="#">Tympanometry</a>
<a class="dropdown-item" href="#">EEG recording</a>
</div>
</li>
</ul>
</div>
</nav>
{% block content %}{% endblock %}
<script>
// From https://gist.github.com/dharmavir/936328
function getHttpRequestObject()
{
// Define and initialize as false
var xmlHttpRequst = false;
// Mozilla/Safari/Non-IE
if (window.XMLHttpRequest)
{
xmlHttpRequst = new XMLHttpRequest();
}
// IE
else if (window.ActiveXObject)
{
xmlHttpRequst = new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlHttpRequst;
}
// Does the AJAX call to URL specific with rest of the parameters
function doAjax(url, method, responseHandler, data)
{
// Set the variables
url = url || "";
method = method || "GET";
async = true;
data = data || null;
if(url == "") {
alert("URL can not be null/blank");
return false;
}
var xmlHttpRequest = getHttpRequestObject();
// If AJAX supported
if(xmlHttpRequest != false) {
xmlHttpRequest.open(method, url, async);
// Set request header (optional if GET method is used)
if(method == "POST") {
xmlHttpRequest.setRequestHeader("Content-Type", "application/json");
}
// Assign (or define) response-handler/callback when ReadyState is changed.
xmlHttpRequest.onreadystatechange = responseHandler;
// Send data
xmlHttpRequest.send(data);
}
else
{
alert("Please use browser with Ajax support.!");
}
}
</script>
</body>
</html>
+92
View File
@@ -0,0 +1,92 @@
{% extends 'index.html' %}
{% block content %}
<div class="card">
<div id="main-div" class="card-body">
<form action="{{ url_for('matDecStim') }}" method="POST">
<div class="form-group">
<label for="snr_num">Number of SNRs:</label>
<br>
<input id="snr_num" name="snr_num" type="number" value="5" style="width:85%">
</div>
<div class="form-group">
<label for="snr_len">Length of SNRs: </label>
<br>
<input id="snr_len" name="snr_len" type="number" value="15" style="width:85%">
</div>
<div class="form-group">
<label for="n_part">Number of participants: </label>
<br>
<input id="n_part" name="n_part" type="number" value="70" style="width:85%">
</div>
<div class="form-group">
<label for="open-mat-folder-container">Matrix data folder: </label>
<br>
<input type="text" id="mat-dir" name='mat_dir' style="width:85%"></input>
<button type="button" id="mat-dir-button" class="btn btn-primary">Browse...</button>
</div>
<div class="form-group">
<label for="open-save-folder-container">New data generation folder: </label>
<br>
<input type="text" id="save-dir" name='save_dir' style="width:85%"></input>
<button type="button" id="save-dir-button" class="btn btn-primary">Browse...</button>
</div>
<div class="form-group">
<button type="button" id="process-button" class="btn btn-primary">Process</button>
<div>
<div class="form-group">
<div id="progress-div" class="progress">
<div id="progress" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%"></div>
</div>
</div>
</form>
</div>
</div>
<script>
$(document).ready(function(){
// Initialise socketio with a namespace called "main"
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
// Catch progress bar update messages
socket.on('update-progress', function(msg) {
// Update width of progress bar
$('#progress').css("width", msg.data);
});
// Catch message when asynchronous process is complete
socket.on('processing-complete', function(msg) {
// Re-enable all inputs
$('#main-div').find('input, textarea, button, select').removeAttr('disabled');
});
$('#process-button').click(function(event) {
// Disable all inputs whilst processing
$('#main-div').find('input, textarea, button, select').attr('disabled','disabled');
// Send message to call stimulus generation function in Python
socket.emit('run_mat_stim_gen', {data: "YES"});
return false;
});
$('#save-dir-button').click(function(event) {
// Send message to call stimulus generation function in Python
socket.emit('open_save_dialog');
return false;
})
socket.on('save-dialog-resp', function(msg) {
// Set form test to filepath returned by dialog
document.getElementById("save-dir").value = msg.data
});
$('#mat-dir-button').click(function(event) {
// Send message to call stimulus generation function in Python
socket.emit('open_mat_dialog');
return false;
})
socket.on('mat-dialog-resp', function(msg) {
// Set form test to filepath returned by dialog
document.getElementById("mat-dir").value = msg.data
});
});
</script>
{% endblock %}