-
Notifications
You must be signed in to change notification settings - Fork 0
/
sciedu.py
469 lines (398 loc) · 17.4 KB
/
sciedu.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
"""
Science Edu Tools
Copyright Team SciEdu
This program uses Python 2.7 and requires the following packages:
pyqtgraph (that requires numpy, scipy, PyQt4 or PySide), pyserial
"""
#import pyqtgraph and qt stuff
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
from pyqtgraph.dockarea import *
from pyqtgraph.flowchart import Flowchart
import pyqtgraph.flowchart.library as fclib
#import other necessary stuff
import os # for paths etc
from PyQt4 import QtWebKit # For QWebView
from functools import partial # For freezing of function parameters
#import own python files
import global_data
from controller_widget import ControllerWidget
from data_structures import AssignmentGroup
from data_structures import Assignment
from data_structures import Exercise
# from oscilloscope import Oscilloscope
from nodes import OscilloscopeNode
from nodes import FilterNode
from nodes import RectifierNode
from nodes import DCBlockNode
from nodes import CharToBinaryNode
from nodes import BinaryToCharNode
from nodes import ParityNode
from nodes import CheckParityNode
from nodes import FFTNode
from nodes import SigGenNode
from nodes import LineEncoderNode
from nodes import AmplifierNode
from nodes import DigiAdderNode
from nodes import NoiseNode
#define constants
WINDOW_DEFAULT_WIDTH = 1000
WINDOW_DEFAULT_HEIGHT = 500
VERSION_ID = '0.21b'
#define variables
#################################
# Load assignment data into variables
#################################
assignment_groups = []
# Loop through assignment group folders until they don't exist anymore, starting from "assignments/1"
directory_was_found = True
counter = 0
while directory_was_found:
counter += 1
assignment_group_path = "content" + os.sep + "groups" + os.sep + str(counter)
# print 'Checking for existance of ' + assignment_group_path
directory_was_found = os.path.isdir(assignment_group_path)
if directory_was_found:
# print 'It exists!'
# Read assignment groups metadata from a file
metadata_path = assignment_group_path + os.sep + "METADATA"
with open(metadata_path) as f:
content = f.readlines()
for line in content:
if line.split('|')[0] == "NAME":
assignment_group_name = line.split('|')[1].rstrip()
elif line.split('|')[0] == "DESCRIPTION":
assignment_group_description = line.split('|')[1].rstrip()
# Create new assignment group
new_assignment_group = AssignmentGroup(name=assignment_group_name, description=assignment_group_description)
# Append assignments to assignment group by looping
assignment_counter = 0
assignment_was_found = True
while assignment_was_found:
assignment_counter += 1
assignment_path = "content"+os.sep+"groups"+os.sep+str(counter)+os.sep+str(assignment_counter)
# print 'Checking for existance of ' + assignment_path
assignment_was_found = os.path.isdir(assignment_path)
if assignment_was_found:
# print 'It exists!'
# Read assignments metadata from file
metadata_path = assignment_path + os.sep + "METADATA"
with open(metadata_path) as f:
content = f.readlines()
for line in content:
if line.split('|')[0] == "NAME":
assignment_name = line.split('|')[1].rstrip()
elif line.split('|')[0] == "DESCRIPTION":
assignment_description = line.split('|')[1].rstrip()
new_assignment = Assignment(name=assignment_name, description=assignment_description, background_url=assignment_path+os.sep+"background.html")
# similarly loop through exercises
exercise_counter = 0
exercise_was_found = True
while exercise_was_found:
exercise_counter += 1
exercise_path = "content"+os.sep+"groups"+os.sep+str(counter)+os.sep+str(assignment_counter)+os.sep+str(exercise_counter)
# print 'Checking for existance of ' + exercise_path
exercise_was_found = os.path.isdir(exercise_path)
if exercise_was_found:
# print 'It exists!'
# Read assignments metadata from file
metadata_path = exercise_path + os.sep + "METADATA"
with open(metadata_path) as f:
content = f.readlines()
for line in content:
if line.split('|')[0] == "NAME":
exercise_name = line.split('|')[1].rstrip()
elif line.split('|')[0] == "DESCRIPTION":
exercise_description = line.split('|')[1].rstrip()
new_exercise = Exercise(name=exercise_name, description=exercise_description, instructions_url=exercise_path+os.sep+"instructions.html")
new_assignment.exercises.append(new_exercise)
new_assignment_group.assignments.append(new_assignment)
assignment_groups.append(new_assignment_group)
# Print the assignment tree
#print "Loaded file structure:"
#for group in assignment_groups:
# print "Group name: " + group.name + ", description: " + group.description
# for assignment in group.assignments:
# print "\tAssignment name: " + assignment.name + ", description: " + assignment.description + ", background path: " + assignment.background_url
# for exercise in assignment.exercises:
# print "\t\tExercise name: " + exercise.name + ", description: " + exercise.description + ", instructions path: " + exercise.instructions_url
##################################
# End of data loading
##################################
# Init current exercise
current_assignment_group = assignment_groups[0]
current_assignment = current_assignment_group.assignments[0]
current_exercise = current_assignment.exercises[0]
# Begin PyQtGraph application
#app = QtGui.QApplication([])
win = QtGui.QMainWindow()
#area = DockArea()
win.setCentralWidget(global_data.area)
#win.showFullScreen()
#win.showMaximized()
win.resize(WINDOW_DEFAULT_WIDTH, WINDOW_DEFAULT_HEIGHT)
# Exercise name label
label = QtGui.QLabel(current_exercise.name)
# Create fixed docks
ex_info = Dock("Instructions") # give this dock the minimum possible size
background_info = Dock("Background")
controller = Dock("Controller")
d3 = Dock("Node Controls")
flowchart_dock = Dock("Connections")
# Place docks on screen
global_data.area.addDock(ex_info, 'left')
global_data.area.addDock(background_info, 'above', ex_info)
global_data.area.addDock(d3, 'right', ex_info)
global_data.area.addDock(controller, 'bottom', d3)
global_data.area.addDock(global_data.tool_dock, 'right')
global_data.area.addDock(flowchart_dock, 'bottom', global_data.tool_dock)
## Add widgets into each dock
# Add instructions widget for exercise
instructions = QtWebKit.QWebView()
# add the widget to a slot on the window
w1 = pg.LayoutWidget()
w1.addWidget(instructions, row=2, col=0)
ex_info.addWidget(w1)
# Add background widget for assignment
background = QtWebKit.QWebView()
background_info.addWidget(background)
####Chaged:Veronika
## restore button
#restoreBtn = QtGui.QPushButton('Restore default view')
#restoreBtn.setEnabled(False)
#w1.addWidget(label, row=0, col=0)
##w1.addWidget(restoreBtn, row=3, col=0)
####
state = None
# Save view state
def save():
global state
state = global_data.area.saveState()
#restoreBtn.setEnabled(True)
# Load view state
def load():
global state
global_data.area.restoreState(state)
####restoreBtn.clicked.connect(load)
# Save the default state of view of main window
save()
# Create and Add a ControllerWidget (for visual and serial communication)
controller_w = ControllerWidget()
controller.addWidget(controller_w)
#####################################
# Create Flow Chart and components
#####################################
# Create flowchart, define input/output terminals
fc = Flowchart(terminals={
#'sigOut': {'io': 'in'},
#'sigOut2': {'io': 'in'}#,
#'sigIn': {'io': 'out'} #We don't currently need any outputs from FC
}, name='Connections')
# Remove the unnecessary input and output nodes
fc.removeNode(fc.inputNode)
fc.removeNode(fc.outputNode)
flowchart = fc.widget()
d3.addWidget(flowchart)
flowchart_dock.addWidget(fc.widget().chartWidget)
#Register own node types
fclib.registerNodeType(OscilloscopeNode, [('SciEdu',)])
fclib.registerNodeType(FilterNode, [('SciEdu',)])
fclib.registerNodeType(CharToBinaryNode, [('SciEdu',)])
# fclib.registerNodeType(BinaryToCharNode, [('SciEdu',)]) # TODO
fclib.registerNodeType(ParityNode, [('SciEdu',)])
fclib.registerNodeType(CheckParityNode, [('SciEdu',)])
fclib.registerNodeType(FFTNode, [('SciEdu',)])
fclib.registerNodeType(SigGenNode, [('SciEdu',)])
fclib.registerNodeType(AmplifierNode, [('SciEdu',)])
fclib.registerNodeType(LineEncoderNode, [('SciEdu',)])
fclib.registerNodeType(RectifierNode, [('SciEdu',)])
fclib.registerNodeType(DCBlockNode, [('SciEdu',)])
fclib.registerNodeType(DigiAdderNode, [('SciEdu',)])
fclib.registerNodeType(NoiseNode, [('SciEdu',)])
# Test thread generation (Not in use now)
#import time
#class WorkThread(QtCore.QThread):
# def __init__(self, node):
# QtCore.QThread.__init__(self)
# self.node = node
# def __del__(self):
# self.wait()
# def run(self):
# running = True
# print("update ")
# while running:
# self.node.updateSignal()
# time.sleep(0.0001)
#Exiting thread now, work is finished
#self.terminate() # not necessary
#wt = WorkThread(signal)
#wt.start()
#Find all signals and update them TODO
#def updateSignals():
#nodes = fc.nodes()
#for node in nodes:
# if nodes[node.nodeName] == 'SigGen':
# nodes[node.nodeName].updateSignal()
# signal1.updateSignal()
# signal2.updateSignal()
#Create and init update timer
#timer = QtCore.QTimer()
#timer.timeout.connect(updateSignals)
#timer.start(10)
# Create and add oscilloscope 1
#osc = Oscilloscope()
#d4.addWidget(osc)
# Add a plotwidget for it to FC
#osc_node = fc.createNode('PlotWidget', name='Oscilloscope 1', pos=(100, 100))
# Connect the node data to osc's plot
#osc_node.setPlot(osc.pwidget)
# Create and add oscilloscope 2
# Add a plotwidget for it to FC
#osc_node2 = fc.createNode('PlotWidget', name='Oscilloscope 2', pos=(100, -100))
# Connect the node data to osc's plot
#osc_node2.setPlot(osc.pwidget2)
# Create pre-made connections (Might not be necessary for most exercises)
#fc.connectTerminals(fc['sigOut'], fftNode['In'])
#########################################
# End flow chart
#########################################
#########################################
# Start of group selection window
#########################################
# Create the load up screen where user selects the group and assignment
load_window = QtGui.QMainWindow()
#load_area = DockArea()
load_window.resize(WINDOW_DEFAULT_WIDTH, WINDOW_DEFAULT_HEIGHT)
load_window.setWindowTitle('Sci edu ' + VERSION_ID)
# Create group selection widget
group_selection_widget = QtGui.QWidget()
load_group_label = QtGui.QLabel('Welcome to SciEdu ' + VERSION_ID + '! Please select the group of assignments.')
load_assignment_label = QtGui.QLabel('Please select the assignment.')
group_selection_layout = QtGui.QGridLayout()
# Generate loading menu
def setup_group_selection():
# Add content
layout = QtGui.QGridLayout()
layout.addWidget(load_group_label, 0, 0, 1, 2)
# Add each group
counter = 1
for g in assignment_groups:
button = QtGui.QPushButton(g.name)
load_group(g)
button.clicked.connect(partial(load_group, g))
group_label = QtGui.QLabel(g.description)
layout.addWidget(button, counter, 0)
layout.addWidget(group_label, counter, 1)
counter += 1
#return layout
global group_selection_layout
group_selection_layout = layout
# Set group selection widget to load windows content
global group_selection_widget
group_selection_widget.setLayout(group_selection_layout)
global load_window
load_window.setCentralWidget(group_selection_widget)
load_window.showMaximized()
def load_group(group):
print "Loading group " + group.name
global current_assignment_group
current_assignment_group = group
group_widget = QtGui.QWidget()
group_layout = QtGui.QGridLayout()
# Add each assignment
counter = 1
for a in current_assignment_group.assignments:
button = QtGui.QPushButton(a.name)
# button press triggers update of instructions and background and shows the main window
button.clicked.connect(partial(load_assignment, a))
global group_label
group_label = QtGui.QLabel(a.description)
group_layout.addWidget(button, counter, 0)
group_layout.addWidget(group_label, counter, 1)
counter += 1
group_widget.setLayout(group_layout)
load_window.setCentralWidget(group_widget)
def load_assignment(assignment):
print "Loading assignment " + assignment.name
# Update current assignment and exercise
global current_assignment
current_assignment = assignment
global current_exercise
current_exercise = assignment.exercises[0]
# Load relevant instructions and background. Exercise 1 is loaded by default
instructions.load(QtCore.QUrl.fromLocalFile(os.getcwd() + os.sep + current_exercise.instructions_url))
background.load(QtCore.QUrl.fromLocalFile(os.getcwd() + os.sep + assignment.background_url))
# Update info label
label.setText(current_exercise.name + ': ' + current_exercise.description)
### DROP DOWN MENU
menubar = win.menuBar()
# Generate exercise drop down menu
exerciseMenu = menubar.addMenu('&Exercises')
# Add exercises to menu
for e in assignment.exercises:
load_exercise_action = QtGui.QAction(QtCore.QString(e.name), exerciseMenu)
load_exercise_action.setStatusTip('Load exercise ' + e.name)
# What happens when we load an exercise from the drop down menu
def loadExercise(ex):
#Set info label
label.setText(ex.name + ': ' + ex.description)
# Set instructions
instructions.load(QtCore.QUrl.fromLocalFile(os.getcwd() + os.sep + ex.instructions_url))
# Set window title
win.setWindowTitle('Sci edu ' + VERSION_ID + ": " + ex.name)
load_exercise_action.triggered.connect(partial(loadExercise, e))
exerciseMenu.addAction(load_exercise_action)
# fileMenu.addAction(exitAction)
viewMenu = menubar.addMenu('&View')
##########Veronika start-- MOVE RESET FUNCTIONALITY TO THE DROP DOWN MENU
resetMenu = menubar.addMenu('&Reset')
load_reset_action = QtGui.QAction(QtCore.QString('&Reset Default View'), resetMenu)
resetMenu.addAction(load_reset_action)
load_reset_action.triggered.connect(load)
##########Veronika end
# fileMenu.addAction(exitAction)
helpMenu = menubar.addMenu('&Help')
########## Veronika start -- ADD TOOLBAR
toolBar = QtGui.QToolBar(win)
toolBar.setObjectName(QtCore.QString("toolBar"))
win.addToolBar(QtCore.Qt.TopToolBarArea, toolBar)
# create an action object Oscilloscope
actionReset = QtGui.QAction(win)
#add an icon
iconReset = QtGui.QIcon()
iconReset.addPixmap(QtGui.QPixmap(QtCore.QString(":/icons/reset.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
actionReset.setIcon(iconReset)
actionReset.setObjectName(QtCore.QString("actionReset"))
#Activate the trigger
actionReset.triggered.connect(load)
#Add above created actions to the tool bar
toolBar.addAction(actionReset)
toolBar.addSeparator()
##QtCore.QObject.connect(actionOscilloscope, QtCore.SIGNAL(QtCore.QString("triggered()")), Oscilloscope.show)
########## Veronika end
# Hide load window and show main window
win.setWindowTitle('Sci edu ' + VERSION_ID + ": " + current_exercise.name)
#win.show()
win.showMaximized()
load_window.hide()
# at first init group selection
#group_selection_layout = setup_group_selection()
setup_group_selection()
# Set group selection widget to load windows content
#group_selection_widget.setLayout(group_selection_layout)
#load_window.setCentralWidget(group_selection_widget)
#########################################
# End of group selection window
#########################################
## assignment selection button
#changeAssignmentBtn = QtGui.QPushButton('Change assignment')
#changeAssignmentBtn.setEnabled(False) # TODO doesn't work
#w1.addWidget(changeAssignmentBtn, row=3, col=1)
#changeAssignmentBtn.clicked.connect(setup_group_selection)
# Show loading window
#load_window.show()
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()