99import random
1010import logging
1111import warnings
12+ import webbrowser
1213
1314from pylsl import StreamInfo , StreamOutlet , local_clock
1415from PyQt5 import QtWidgets , QtGui , QtCore , QtMultimedia
3334cues_directory .mkdir (exist_ok = True )
3435dreams_directory .mkdir (exist_ok = True )
3536
37+ COMMON_EVENT_CODES = {
38+ "REM detected" : 12 ,
39+ "Tech in room" : 12 ,
40+ "TLR training start" : 12 ,
41+ "TLR training end" : 12 ,
42+ "LRLR detected" : 12 ,
43+ "Sleep onset" : 34 ,
44+ "Lights off" : 45 ,
45+ "Lights on" : 56 ,
46+ }
47+
48+ COMMON_EVENT_TIPS = {
49+ "Lights off" : "Mark the beginning of sleep session" ,
50+ "Lights on" : "Mark the end of sleep session" ,
51+ "TLR training start" : "Mark the start of Targeted Lucidity Reactivation training" ,
52+ "TLR training end" : "Mark the end of Targeted Lucidity Reactivation training" ,
53+ "Tech in room" : "Mark the entry of an experimenter/technician in the participant bedroom" ,
54+ "Sleep onset" : "Mark observed sleep onset" ,
55+ "REM detected" : "Mark observed REM" ,
56+ "LRLR detected" : "Mark an observed left-right-left-right lucid signal" ,
57+ "Note" : "Mark a note and enter free text" ,
58+ }
59+
3660
3761#########################################################
3862######### Create some custom PyQt classes #########
@@ -81,25 +105,6 @@ def getInputs(self):
81105 return subject_int , session_int
82106
83107
84- def showAboutPopup ():
85- """'About SMACC' popup window."""
86- text = (
87- f"Sleep Manipulation and Communication Clickything\n "
88- f"version: v{ VERSION } "
89- f"https://github.com/remrama/smacc\n "
90- )
91- win = QtWidgets .QMessageBox ()
92- win .setWindowTitle ("About SMACC" )
93- win .setIcon (QtWidgets .QMessageBox .Information )
94- win .setStandardButtons (QtWidgets .QMessageBox .Ok | QtWidgets .QMessageBox .Close )
95- win .setDefaultButton (QtWidgets .QMessageBox .Close )
96- win .setInformativeText (text )
97- # win.setDetailedText("detailshere")
98- # win.setStyleSheet("QLabel{min-width:500 px; font-size: 24px;} QPushButton{ width:250px; font-size: 18px; }");
99- # win.setGeometry(200, 150, 100, 40)
100- win .exec_ ()
101-
102-
103108
104109#####################################
105110######### Main window #########
@@ -142,8 +147,9 @@ def __init__(self, subject_id, session_id):
142147 def showErrorPopup (self , short_msg , long_msg = None ):
143148 # self.log_info_msg("ERROR")
144149 win = QtWidgets .QMessageBox ()
145- win .setIcon (QtWidgets .QMessageBox .Warning )
146- # win.setIconPixmap(QtGui.QPixmap("./img/fish.ico"))
150+ # # win.setIcon(QtWidgets.QMessageBox.Question)
151+ # win.setWindowIcon(QtGui.QIcon("./thumb-small.png"))
152+ # win.setIconPixmap(QtGui.QPixmap("./thumb.png"))
147153 win .setText (short_msg )
148154 if long_msg is not None :
149155 win .setInformativeText (long_msg )
@@ -214,7 +220,7 @@ def init_main_window(self):
214220
215221 aboutAction = QtWidgets .QAction (self .style ().standardIcon (getattr (QtWidgets .QStyle , "SP_MessageBoxInformation" )), "&About" , self )
216222 aboutAction .setStatusTip ("About SMACC" )
217- aboutAction .triggered .connect (showAboutPopup )
223+ aboutAction .triggered .connect (self . show_about_popup )
218224
219225 quitAction = QtWidgets .QAction (self .style ().standardIcon (getattr (QtWidgets .QStyle , "SP_BrowserStop" )), "&Quit" , self )
220226 quitAction .setShortcut ("Ctrl+Q" )
@@ -356,7 +362,7 @@ def init_main_window(self):
356362 # # outputMenu = audioMenu.addMenu(QtGui.QIcon("./img/output.png"), "&Output device")
357363
358364 ########################################################################
359- # AUDIO RECORDING/MICROPHONE WIDGET
365+ # DREAM REPORT WIDGET
360366 ########################################################################
361367
362368 recordingtitleLabel = QtWidgets .QLabel ("Dream recording" )
@@ -377,11 +383,15 @@ def init_main_window(self):
377383 micrecordButton .setCheckable (True )
378384 micrecordButton .clicked .connect (self .start_or_stop_recording )
379385
386+ surveyurlEdit = QtWidgets .QLineEdit (self )
387+ self .surveyurlEdit = surveyurlEdit
388+
380389 microphoneLayout = QtWidgets .QFormLayout ()
381390 microphoneLayout .setLabelAlignment (QtCore .Qt .AlignRight )
382391 microphoneLayout .setLabelAlignment (QtCore .Qt .AlignRight )
383392 microphoneLayout .addRow (recordingtitleLabel )
384393 microphoneLayout .addRow ("Device:" , available_microphones_dropdown )
394+ microphoneLayout .addRow ("Survey URL:" , surveyurlEdit )
385395 microphoneLayout .addRow ("Play/Stop:" , micrecordButton )
386396
387397 ########################################################################
@@ -455,19 +465,11 @@ def init_main_window(self):
455465 eventmarkertitleLabel .setAlignment (QtCore .Qt .AlignCenter )
456466 eventmarkertitleLabel .setStyleSheet ("font: 18pt" )
457467
458- common_events = {
459- "Awakening" : "Mark an awakening (shortcut 1)" ,
460- "LRLR" : "Mark a left-right-left-right lucid signal" ,
461- "SleepOnset" : "Mark observed sleep onset" ,
462- "LightsOff" : "Mark the beginning of sleep session" ,
463- "LightsOn" : "Mark the end of sleep session" ,
464- "Note" : "Open a text box and timestamp a note." ,
465- }
466-
467468 eventsLayout = QtWidgets .QGridLayout ()
468469 eventsLayout .addWidget (eventmarkertitleLabel , 0 , 0 , 1 , 2 )
469- for i , (event , tip ) in enumerate (common_events .items ()):
470- if i > len (common_events ) / 2 :
470+ n_events = len (COMMON_EVENT_TIPS )
471+ for i , (event , tip ) in enumerate (COMMON_EVENT_TIPS .items ()):
472+ if i > n_events / 2 :
471473 row = 1
472474 col += 1
473475 shortcut = str (i + 1 )
@@ -481,7 +483,7 @@ def init_main_window(self):
481483 else :
482484 button .clicked .connect (self .handle_event_button )
483485 row = 1 + i
484- if i >= (halfsize := int (len ( common_events ) / 2 )):
486+ if i >= (halfsize := int (n_events / 2 )):
485487 row -= halfsize
486488 col = 1 if i >= halfsize else 0
487489 eventsLayout .addWidget (button , row , col )
@@ -534,17 +536,24 @@ def init_main_window(self):
534536 self .resize (1200 , 500 )
535537 self .show ()
536538
539+ def show_about_popup (self ):
540+ win = QtWidgets .QMessageBox ()
541+ # win.setIcon(QtWidgets.QMessageBox.Question)
542+ # win.setWindowIcon(QtGui.QIcon("./thumb-small.png"))
543+ # win.setIconPixmap(QtGui.QPixmap("./thumb.png"))
544+ win .setStandardButtons (QtWidgets .QMessageBox .Ok )
545+ win .setWindowTitle ("About SMACC" )
546+ win .setText ("Sleep Manipulation and Communication Clickything" )
547+ win .setInformativeText (f"version: v{ VERSION } \n https://github.com/remrama/smacc" )
548+ # win.setDetailedText("detailshere")
549+ # win.setStyleSheet("QLabel{min-width:500 px; font-size: 24px;} QPushButton{ width:250px; font-size: 18px; }");
550+ # win.setGeometry(200, 150, 100, 40)
551+ win .exec_ ()
552+
537553 def handle_event_button (self ):
538554 sender = self .sender ()
539555 text = sender .text ().split ("(" )[0 ].strip ()
540- port_codes = {
541- "Awakening" : 12 ,
542- "LRLR" : 23 ,
543- "SleepOnset" : 34 ,
544- "LightsOff" : 45 ,
545- "LightsOn" : 56 ,
546- }
547- code = port_codes [text ]
556+ code = COMMON_EVENT_CODES [text ]
548557 self .send_event_marker (code , text )
549558
550559 def open_wav_selector (self ):
@@ -827,6 +836,8 @@ def update_microphone_status(self, state):
827836 def start_or_stop_recording (self ):
828837 self .record () # This will start OR stop recording, whichever is not currently happening
829838 if self .sender ().isChecked ():
839+ if (survey_url := self .surveyurlEdit .text ()):
840+ webbrowser .open (survey_url , new = 1 , autoraise = False )
830841 port_msg = "DreamReportStarted"
831842 else :
832843 port_msg = "DreamReportStopped"
0 commit comments