def onRun(self, event): if DEBUGGING: print('ScriptPanel.onRun()') event.Skip() obj = wx.FindWindowByName( "fn", self ) script_fn = obj.GetValue().strip() if path.isfile(script_fn) == False: show_msg("File, %s, doesn't exist"%(script_fn)) return f = open(script_fn, 'r') fileScript = f.read() f.close() currScript = self.stc.GetText() # current script in the script panel if fileScript != currScript: # script from file and script panel is different dlg = PopupDialog(inString="This will run the file, %s.\nThe contents of the file and the current script in this script panel is different.\nPress Okay to overwrite the file with the current script and run.\nPress Cancel to run the file as it is."%(script_fn), title="Overwriting", size=(400,200), cancel_btn=True) result = dlg.ShowModal() dlg.Destroy() if result == wx.ID_OK: self.onSave(None, flag_overwrite=True) cmd = ['pythonw', script_fn] stdout = '' try: p = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE) stdout, stderr = p.communicate() p.terminate() p.wait() except: pass title = "stdout" if 'error' in str(stdout).lower(): title += ": ERROR" show_msg(msg=stdout.strip(), size=(700,350), title=title)
def onSave(self, event, flag_overwrite=False): if DEBUGGING: print('ScriptPanel.onSave()') if event != None: event.Skip() obj = wx.FindWindowByName( "fn", self ) fn = obj.GetValue().strip() if fn == '': dlg = wx.MessageDialog(self, 'Filename is empty.', style=wx.OK|wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() return savePath = path.join( getcwd(), path.basename(fn) ) file_exists = path.isfile(savePath) if file_exists: if flag_overwrite != True: # if it's not already instructed to overwrite ### ask whether to overwrite dlg = PopupDialog(inString="File already exists. Overwrite it?", size=(300,100), cancel_btn=True) result = dlg.ShowModal() dlg.Destroy() if result == wx.ID_CANCEL: return txt = self.stc.GetText() f = open(savePath, 'wb') f.write(txt.encode('utf8')) f.close() if txt != self.scriptChangedByMainPanel: # manual script change occurred self.updateMainPanelFromScript(txt) # update main panel widgets with the script text, because user might have edited script manually. self.scriptChangedByMainPanel = txt if not file_exists: show_msg("File is saved at\n%s"%(savePath))
def onNavMarkers(self, event): if DEBUGGING: print('ScriptPanel.onNavMarkers()') if self.markerIds == []: show_msg("No markers found.\n(Markers will be added when a marker button is pressed in the center panel or new script lines are added.)", size=(300,170)) return if type(event) == str: obj_name = event else: event.Skip() obj = event.GetEventObject() obj_name = obj.GetName() ### move screen and caret to the next or prev marker if obj_name == 'nextM': self.cmi += 1 if self.cmi >= len(self.markerIds): self.cmi = 0 elif obj_name == 'prevM': self.cmi -= 1 if self.cmi < 0: self.cmi = len(self.markerIds)-1 line_num = self.stc.MarkerLineFromHandle(self.markerIds[self.cmi]) self.stc.GotoLine(line_num) #if self.stc.GetLineVisible(line_num) == False: # the line is not visible # vl = max(1, line_num-10) # self.stc.SetFirstVisibleLine(vl) self.stc.SetSelection(self.stc.GetCurrentPos(), self.stc.GetLineEndPosition(line_num))
def onReplace(self, event): ''' search a string in the current script text & replace it with the typed text in replaceTxt ''' event.Skip() searchTxt, idx1 = self.onSearch(None) if idx1 == -1: show_msg("The search string, %s, is not found in the current script."%(searchTxt), (250,150)) return evtObjName = event.GetEventObject().GetName() replaceTxt = wx.FindWindowByName("replaceTxt").GetValue().strip() if evtObjName == "replaceOneBtn": self.stc.Replace(idx1, idx1+len(searchTxt), replaceTxt) self.stc.GotoPos(idx1) self.stc.SetSelection(idx1, idx1+len(replaceTxt)) elif evtObjName == "replaceAllBtn": cnt = 1 lastIdx = -1 while idx1 != -1: self.stc.Replace(idx1, idx1+len(searchTxt), replaceTxt) lastIdx = copy(idx1) searchTxt, idx1 = self.onSearch(None) if idx1 == -1: show_msg("%i found texts are replaced."%(cnt), (250,100)) cnt += 1 self.stc.GotoPos(lastIdx) self.stc.SetSelection(lastIdx, lastIdx+len(replaceTxt)) self.stc.SetFocus()
def onHelp(self, event): ''' show descriptions of a selected item ''' if DEBUGGING: print('ItemPanel.onHelp()') obj_name = event.GetEventObject().GetName() item = obj_name.replace("_help_btn", "") for i in range(len(self.item_info)): if item in self.item_info[i].keys(): show_msg(self.item_info[i][item]["desc"], (400, 250)) break
def onLoad(self, event): if DEBUGGING: print('ScriptPanel.onLoad()') event.Skip() f = wx.FileDialog(self, "Choose a Python file you saved before.", getcwd(), wildcard="Python files (*.py)|*.py", style=wx.FD_DEFAULT_STYLE|wx.FD_OPEN|wx.FD_FILE_MUST_EXIST) if f.ShowModal() == wx.ID_CANCEL: return fp = f.GetPath() f = open(fp, "r") txt = f.read() f.close() if (not 'class Experimenter' in txt) or (not '#[flag:' in txt): show_msg("The chosen file is not an Experimenter Python file.") return self.updateMainPanelFromScript(txt) # update main panel widgets with the script text self.stc.SetText(txt) # load the script text to STC self.stc.SetFirstVisibleLine(0) self.stc.ScrollToColumn(0)
def onCheck(self, event): ''' Fisnish_setup button is clicked. Process some check-up procedures. ''' if DEBUGGING: print('SetupStimuliDialog.onCheck()') rv = self.return_val if rv["number_of_trials"] == 0 or rv[ "number_of_experimental_stimuli"] + rv[ "number_of_response_stimuli"] == 0: show_msg( "'Number of trials' should be greater than zero and there should be, at least, one stimulus." ) return if 'mov' in rv["types_of_es"]: rslt = self.query("movie_module", (300, 300)) if rslt == None: return rv["movie_module"] = rslt ### if response stimulus (such as 'yes/no' string) is only one (meaning the same string will be used for all trials) ### make it for the number of trials. e.g.) ['yes']*3 ---> ['yes', 'yes', 'yes'] (when number_of_trials == 3) if rv["number_of_trials"] > 1: for pi in range(len(rv["paths_of_rs"])): if len(rv["paths_of_rs"][pi]) == 1: rv["paths_of_rs"][ pi] = rv["paths_of_rs"][pi] * rv["number_of_trials"] if self.rsCorrIdx != -1: # there is an index indicating a folder with correct responses if rv["types_of_rs"][self.rsCorrIdx] != "txt": ### add the correct response tag, "_c", at the end of filename for f in rv["paths_of_rs"][self.rsCorrIdx]: bn = path.basename(f) ext = bn.split(".")[-1] new_bn = bn.replace("." + ext, "") if (new_bn[-2:] == "_c") or ("_c-" in new_bn): continue # filename already has the correct response tag new_bn = new_bn + "_c." + ext new_f = f.replace(bn, new_bn) rename(f, new_f) rv["paths_of_rs"] = new_f event.Skip()
def onSearch(self, event): ''' search a string in the current script text ''' if event != None: event.Skip() searchTxt = wx.FindWindowByName("searchTxt").GetValue().strip() if searchTxt == '': if event == None: return searchTxt, -1 else: return curr_pos = self.stc.GetCurrentPos() if curr_pos > 0: curr_pos += len(searchTxt) txtLen = self.stc.GetTextLength() if curr_pos >= txtLen: idx = self.stc.FindText(0, txtLen, searchTxt ) else: idx = self.stc.FindText(curr_pos, txtLen, searchTxt ) if idx == -1: idx = self.stc.FindText(0, txtLen, searchTxt ) if event == None: return searchTxt, idx # if this function was called by 'onReplace', return found index if idx == -1: show_msg("The search string, %s, is not found in the current script."%(searchTxt), (250,150)) else: self.stc.GotoPos(idx) self.stc.SetSelection(idx, idx+len(searchTxt))
def onRectTextChange(self, event): ''' apply manually changed stimulus rect ''' if DEBUGGING: print('SetupStimuliDialog.onRectTextChange()') obj = event.GetEventObject() objName = obj.GetName() val = obj.GetValue().strip('[]') r = val.split(",") if len(r) != 4: return try: r[0] = float(r[0]) r[1] = float(r[1]) r[2] = int(r[2]) r[3] = int(r[3]) except: show_msg("Invalid number") return if r[0] < 0.0 or r[0] > 1.0 or r[1] < 0.0 or r[1] > 1.0: show_msg("Invalid x/y") return if r[2] < -1 or r[2] == 0 or r[3] < -1 or r[3] == 0: show_msg("Invalid width/height") return if r[3] == -1: hh = self.ds_sz[1] else: hh = r[3] / 2 pos = (int(self.w_sz[0] * r[0]) - obj.GetSize()[0] / 2, int(self.w_sz[1] * r[1]) + hh / 2 + 5) obj.SetPosition(pos) btn = wx.FindWindowByName(objName.replace("_rect_", "_open_btn_"), self) pos = (int(self.w_sz[0] * r[0]) - btn.GetSize()[0] / 2, int(self.w_sz[1] * r[1]) - btn.GetSize()[1] / 2 - self.ds_sz[1] / 2) btn.SetPosition(pos) if objName.startswith('rs'): # response stimulus rect btn = wx.FindWindowByName( objName.replace("_rect_", "_correct_btn_"), self) pos = (int(self.w_sz[0] * r[0]) + self.ds_sz[0] / 2 - btn.GetSize()[0], int(self.w_sz[1] * r[1]) - btn.GetSize()[1] / 2 - self.ds_sz[1] / 2) btn.SetPosition(pos) idx = int(objName.split("_")[-1]) if objName.startswith('es_'): self.return_val["rects_of_es"][idx] = r elif objName.startswith('rs_'): self.return_val["rects_of_rs"][idx] = r self.Refresh()
def onSelectStim(self, event): ''' select and set up stimuli (selecting folder, entering texts, choosing slider, choosing correct response, etc) ''' if DEBUGGING: print('SetupStimuliDialog.onSelectStim()') obj = event.GetEventObject() objName = obj.GetName() ss = objName.split("_") sTag = ss[0] # es (experimental stimuli) or rs (response stimuli) sIdx = int(ss[-1]) tKey = "types_of_%s" % (sTag) pKey = "paths_of_%s" % (sTag) rKey = "rects_of_%s" % (sTag) if sTag == "rs" and self.sliders[sIdx] != None: self.sliders[sIdx].Destroy() self.sliders[sIdx] = None type_of_stim = self.query("type_of_stim", (350, 150), sTag) if type_of_stim == None: return elif type_of_stim == "text": ### enter text stimuli txt_stim = self.query("text_stim", (500, 350)) if txt_stim == None: return txt_stim = [x.strip() for x in txt_stim.split(",")] if len(txt_stim) != 1 and len( txt_stim) != self.return_val["number_of_trials"]: show_msg( "Number of stimuli should match with 'Number of trials' you entered. (Or one in case the same stimulus is used for all trials)." ) return self.return_val[tKey][sIdx] = "txt" self.return_val[pKey][sIdx] = txt_stim elif type_of_stim == "slider": self.return_val[tKey][sIdx] = "slider" self.return_val[pKey][sIdx] = ["slider"] r = self.return_val[rKey][sIdx] w = r[2] if w == -1: w = 300 self.sliders[sIdx] = wx.Slider(self, -1, 5, 0, 10, pos=(1, 1), size=(w, -1), style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS) x = r[0] * self.parent.parent.w_sz[0] - w / 2 y = r[1] * self.parent.parent.w_sz[0] - self.sliders[sIdx].GetSize( )[1] / 2 self.sliders[sIdx].SetPosition((x, y)) rt = [ x.strip() for x in self.rsRectTxts[sIdx].GetValue().strip( "[]").split(",") ] self.rsRectTxts[sIdx].SetValue("[%s, %s, %i, %s]" % (rt[0], rt[1], w, rt[3])) self.return_val[rKey][sIdx] = [ float(rt[0]), float(rt[1]), w, int(rt[3]) ] else: # image ### choose a folder, containing stimuli files for this stimulus dlg = wx.DirDialog(self, "Choose a folder for this stimulus.", self.e_gui_path, wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST) if dlg.ShowModal() == wx.ID_CANCEL: return cnt = [0, 0, 0] # img, snd, mov cnt_lbl = ["img", "snd", "mov"] sfp = [] # stimuli file path fl = sorted(glob(path.join(dlg.GetPath(), "*.*"))) for f in fl: ext = path.basename(f).split('.')[-1] if ext in self.parent.parent.allowed_img_ext: cnt[0] += 1 elif ext in self.parent.parent.allowed_snd_ext: cnt[1] += 1 elif ext in self.parent.parent.allowed_mov_ext: cnt[2] += 1 if sum(cnt) == 0: show_msg( "No stimuli files is recognized in the selected folder.") return max_cnt = max(cnt) if max_cnt != 1 and max_cnt != self.return_val["number_of_trials"]: show_msg( "Number of stimuli should match with 'Number of trials' you entered. (Or one in case the same stimulus is used for all trials)." ) return st = cnt_lbl[cnt.index(max_cnt)] # stimulus type if sTag == "rs" and st != 'img': show_msg( "Response stimulus could be image, text, or slider. Sound or movie is not allowed." ) return if st == "img": allowed_ext = self.parent.parent.allowed_img_ext elif st == "snd": allowed_ext = self.parent.parent.allowed_snd_ext elif st == "mov": allowed_ext = self.parent.parent.allowed_mov_ext for f in fl: ext = path.basename(f).split('.')[-1] if ext in allowed_ext: sfp.append(f) self.return_val[tKey][sIdx] = st self.return_val[pKey][sIdx] = sfp tName = "%s_rect_%i" % (sTag, sIdx) rectObj = wx.FindWindowByName(tName, self) if st == "snd": rectObj.Disable() else: rectObj.Enable() if type_of_stim == "image": self.rsCorrectBtns[sIdx].Show() else: self.rsCorrectBtns[sIdx].Hide() self.Refresh()
def onClickApply(self, event): ''' clicked apply button (for number_of_trials, number_of_experimental_stimuli or number_of_response_stimuli) ''' if DEBUGGING: print('SetupStimuliDialog.onClickApply()') for key in self.main_param: valObj = wx.FindWindowByName(key, self) val = valObj.GetValue() val_int = None try: val_int = int(val) except: pass if val_int == None: valObj.SetValue("0") show_msg("%s has invalid number" % (key)) return self.return_val[key] = val_int #objName = event.GetEventObject().GetName() #if objName.startswith("apply_"): key = objName.replace("apply_", "") #else: key = objName if key == "number_of_trials": # if number_of_trials chnages, init other numbers self.return_val["number_of_experimental_stimuli"] = 0 valObj = wx.FindWindowByName("number_of_experimental_stimuli", self) valObj.SetValue("0") self.return_val["number_of_response_stimuli"] = 0 valObj = wx.FindWindowByName("number_of_response_stimuli", self) valObj.SetValue("0") self.return_val["types_of_es"] = [] self.return_val["types_of_rs"] = [] self.return_val["rects_of_es"] = [] self.return_val["rects_of_rs"] = [] self.return_val["paths_of_es"] = [] self.return_val["paths_of_rs"] = [] self.sliders = [] ### set up rects for txt in self.esRectTxts: txt.Destroy() self.esRectTxts = [] for btn in self.esOpenBtns: btn.Destroy() self.esOpenBtns = [] for txt in self.rsRectTxts: txt.Destroy() self.rsRectTxts = [] for btn in self.rsOpenBtns: btn.Destroy() self.rsOpenBtns = [] for btn in self.rsCorrectBtns: btn.Destroy() self.rsCorrectBtns = [] nes = self.return_val["number_of_experimental_stimuli"] nrs = self.return_val["number_of_response_stimuli"] num_of_stim = nes + nrs if num_of_stim == 1: rects = [[0.5, 0.5, -1, -1]] elif num_of_stim == 2: if nes == 1 and nrs == 1: rects = [[0.5, 0.5, -1, -1], [0.5, 0.8, -1, -1]] else: rects = [[0.25, 0.5, -1, -1], [0.75, 0.5, -1, -1]] elif num_of_stim == 3: rects = [[0.5, 0.5, -1, -1], [0.25, 0.8, -1, -1], [0.75, 0.8, -1, -1]] else: columns = sqrt(num_of_stim) rows = int(columns) if columns % 1 > 0: columns += 1 columns = int(columns) rects = [] for r in range(rows): if r == rows - 1: # last row w = 1.0 / (num_of_stim - columns * (rows - 1)) else: w = 1.0 / columns # width for each stimulus h = 1.0 / rows # height for each stimulus for c in range(columns): rects.append([w * c + w / 2, h * r + h / 2, -1, -1]) self.return_val["rects_of_es"] = rects[:nes] self.return_val["rects_of_rs"] = rects[nes:] for si in range(num_of_stim): if si < nes: tName = "es_rect_%i" % (si) else: tName = "rs_rect_%i" % (si - nes) r = rects[si] txt = wx.TextCtrl(self, -1, value="[%.3f, %.3f, -1, -1]" % (r[0], r[1]), name=tName, size=(170, -1), style=wx.TE_PROCESS_ENTER) txt.Bind(wx.EVT_TEXT_ENTER, self.onRectTextChange) pos = (int(self.w_sz[0] * r[0]) - txt.GetSize()[0] / 2, int(self.w_sz[1] * r[1]) + self.ds_sz[1] / 2 + 5) txt.SetPosition(pos) bName = tName.replace("_rect_", "_open_btn_") oBtn = wx.Button(self, -1, label='', name=bName, size=(20, 20)) oBtn.Bind(wx.EVT_LEFT_DOWN, self.onSelectStim) set_img_for_btn( path.join(self.e_gui_path, "input/img_open_folder.png"), oBtn) pos = (int(self.w_sz[0] * r[0]) - oBtn.GetSize()[0] / 2, int(self.w_sz[1] * r[1]) - oBtn.GetSize()[1] / 2 - self.ds_sz[1] / 2) oBtn.SetPosition(pos) lName = tName.replace("_rect_", "_stim_list_") if si >= nes: # this is response stimulus bName = tName.replace("_rect_", "_correct_btn_") cBtn = wx.Button(self, -1, label='', name=bName, size=(20, 20)) cBtn.Bind(wx.EVT_LEFT_DOWN, self.onSelectCorrectStim) set_img_for_btn( path.join(self.e_gui_path, "input/img_apply.png"), cBtn) pos = (int(self.w_sz[0] * r[0]) + self.ds_sz[0] / 2 - cBtn.GetSize()[0], int(self.w_sz[1] * r[1]) - cBtn.GetSize()[1] / 2 - self.ds_sz[1] / 2) cBtn.SetPosition(pos) if si < nes: # this is experimental stimulus self.esRectTxts.append(txt) self.esOpenBtns.append(oBtn) self.return_val["types_of_es"].append(None) self.return_val["paths_of_es"].append([]) else: # response stimulus self.rsRectTxts.append(txt) self.rsOpenBtns.append(oBtn) self.rsCorrectBtns.append(cBtn) self.sliders.append(None) self.return_val["types_of_rs"].append(None) self.return_val["paths_of_rs"].append([]) self.Refresh() self.setting_p.Raise()
def updateMainPanelFromScript(self, txt): ''' Update main panel widgets with contents from script, when laoding script from file or saving occurs. 'txt': script text ''' ### delete (hide from screen) current optional item widgets in main-panel for item in self.parent.iPanel.item_info[1]: btn_name = "%s_del_btn"%(item) del_btn_obj = wx.FindWindowByName( btn_name, self.parent.mPanel ) if del_btn_obj != None: # object found self.parent.mPanel.onDelItem(btn_name) # delete ### update or add items in main-panel with the loaded script # basic items err_msg = "" for item in sorted(self.parent.iPanel.item_info[0].keys()): # iterate basic items idx1 = txt.find("#[flag:%s]"%(item)) if idx1 == -1: # flag was not found err_msg += "#[flag:%s] was not found.\n"%(item) continue idx2 = copy(idx1) while txt[idx1] != '=': idx1 -= 1 # move index to the previous '=' sign val = txt[idx1+1:idx2].strip().replace('\n','').replace(' ','') if val[0] != '[' and val[-1] != ']': # it's not a list if '"' in val: val = val.replace('"', '') # get rid of double quote marks if "'" in val: val = val.replace("'", '') # get rid of single quote marks self.parent.mPanel.setItemVal(item, val) if err_msg != "": err_msg += "\n\n" # stimulus items _list = list(self.parent.iPanel.item_info[2].keys()) _list.remove('s_type') _list.insert(0, 's_type') # s_type;stimulus-type should be processed first, because others (clickable, etc) refers s_type's values for item in _list: # iterate stimulus items idx1 = txt.find("#[flag:%s]"%(item)) if idx1 == -1: # flag was not found err_msg += "#[flag:%s] was not found.\n"%(item) continue idx2 = copy(idx1) while txt[idx1] != '=': idx1 -= 1 # move index to the previous '=' sign val = txt[idx1+1:idx2].strip().replace('\n','').replace(' ','') self.parent.mPanel.add_del_item(item, item_list_idx=2) self.parent.mPanel.setItemVal(item, val) if err_msg != "": err_msg += "\n\n" # optional items for item in sorted(self.parent.iPanel.item_info[1].keys()): # iterate optional items idx1 = txt.find("#[flag:%s]"%(item)) if idx1 == -1: continue # continue, if the flag was not found. idx2 = copy(idx1) while txt[idx1] != '=': idx1 -= 1 # move index to the previous '=' sign val = txt[idx1+1:idx2].strip().replace('\n','').replace(' ','') if val == 'False': continue if val[0] != '[' and val[-1] != ']': # it's not a list if '"' in val: val = val.replace('"', '') # get rid of double quote marks if "'" in val: val = val.replace("'", '') # get rid of single quote marks self.parent.mPanel.add_del_item(item, item_list_idx=1) self.parent.mPanel.setItemVal(item, val) if err_msg != "": show_msg(err_msg) # audio_output idx = txt.find("class Output_AudioData") if idx != -1: # the class was found self.parent.mPanel.items['audio_output'] = "added" # movie idx = txt.find("class MovPlayer") if idx != -1: # the class was found self.parent.mPanel.items['movie'] = "added"
def chkChangedValue(self, event): if DEBUGGING: print('MainPanel.chkChangedValue()') '''Check & process (such as showing error message, updating the script, etc) the entered value When the value was changed by SetValue by code, 'event' will be name of the object(widget) ''' if type(event) == str: obj_name = event obj = wx.FindWindowByName(obj_name, self) else: event.Skip() obj = event.GetEventObject() obj_name = obj.GetName() item = obj_name[:-4] if '_txt' in obj_name: vType, val = self.getItemVal(item) key_found_in_item_info = False for ii in range(len(self.parent.iPanel.item_info)): iInfo = self.parent.iPanel.item_info[ii] if item in iInfo.keys(): key_found_in_item_info = True break err_msg = "" ### check whether the entered value is in the range of values, where it's applicable if key_found_in_item_info == True and iInfo[item]["values"] != None: rng = iInfo[item]["values"] # range of values err_msg = "" _val = None try: _val = int(val) except: pass if _val == None: err_msg += "This value should be an integer.\n" else: if rng[0] > _val or rng[1] < _val: err_msg += "This value should range between %i and %i\n" % ( rng[0], rng[1]) if item in ['clickable', 'rect']: stObj = wx.FindWindowByName("s_type_txt", self) st = stObj.GetValue().replace(' ', '').strip("[]").replace( '"', '').replace("'", "").split(",") # stimulus types if item == 'clickable': ### check values of clickable val = re.sub( '(?i)' + re.escape('true'), 'True', val ) # change 'true' with lower or upper case on any letter to 'True' for boolean value val = re.sub( '(?i)' + re.escape('false'), 'False', val ) # change 'false' with lower or upper case on any letter to 'False' for boolean value obj.SetValue(val) _val = val.strip().strip("[]").split(",") ur = self.getItemVal("user_response")[1] for i in range(len(_val)): if _val[i].strip().lower( ) == "true" and ur != 'mouse_click': err_msg += "Item index %i in 'clickable': user_response is not mouse_click.\n" % ( i) if _val[i].strip().lower() == "true" and st[i].strip( ) == "snd": err_msg += "Item index %i in 'clickable': 'snd' stimulus can't be clicked.\n" % ( i) elif item == 'present_time': ### check values of 'present_time' _val = val.replace(" ", "").strip("[]").split( "],[") # split by stimulus for i in range(len(_val)): _v = _val[i].split( ",") # split the start-time and end-time if len(_v) != 2: err_msg += "Item index %i in 'present_time': Length of an inside list of 'present_time' should be two, start-time & end-time.\n" % ( i) else: for j in range(2): try: _v[j] = int(_v[j]) except: pass if type(_v[0]) != int or type(_v[1]) != int: err_msg += "Item index %i in 'present_time': Items in 'present_time' should be integers (time in milliseconds).\n" % ( i) else: if _v[0] < 1: err_msg += "Item index %i in 'present_time': Start-time, (first item in the inner list), should be one at minimum.\n" % ( i) if _v[1] != -1 and _v[1] <= _v[ 0]: # End-time should be either -1 or larger than the start-time. err_msg += "Item index %i in 'present_time': End-time, (second item in the inner list), should be larger than the start-time.\n" % ( i) elif item == 'rect': ### check values of 'rect' val = re.sub( '(?i)' + re.escape('none'), 'None', val ) # change 'none' with lower or upper case on any letter to 'None' obj.SetValue(val) _val = val.replace(" ", "").strip("[]").split( "],[") # split by stimulus for i in range(len(_val)): _v = _val[i].split(",") # split rect info (x,y,w,h) if len(_v) != 4: err_msg += "Item index %i in 'rect': Length of an inside list of 'rect' should be four (x,y,w,h).\n" % ( i) continue if st[i].strip() == 'snd': if _val[i] != "None,None,None,None": err_msg += "Item index %i in 'rect': 'rect' is not applicable for 'snd' stimulus. It should be None,None,None,None.\n" % ( i) continue else: try: _v[0] = float(_v[0]) _v[1] = float(_v[1]) _v[2] = int(_v[2]) _v[3] = int(_v[3]) except: pass for j in range(len(_v)): if j < 2 and type(_v[j]) != float: err_msg += "x & y coordiantes in 'rect' should be float numbers.\nCheck more info by clicking (i) button next to 'rect' in the lfet panel.\n" elif j >= 2 and type(_v[j]) != int: err_msg += "width & height in 'rect' should be integers.\nCheck more info by clicking (i) button next to 'rect' in the lfet panel.\n" else: if j < 2: # x, y if _v[j] < 0 or _v[ j] > 1: # x, y should between 0.0 and 1.0 err_msg += "x & y in 'rect' should be between 0.0 and 1.0.\nCheck more info by clicking (i) button next to 'rect' in the left panel.\n" else: # w, h if _v[j] != -1 and _v[ j] <= 0: # w, h should be -1 or larger than zero err_msg += "width & height in 'rect' should be larger than zero.\nCheck more info by clicking (i) button next to 'rect' in the left panel.\n" if err_msg != "": break if err_msg != "": show_msg(err_msg, size=(700, 350)) obj.SetValue( str(self.items[item] )) # return the value to the previously stored value return elif '_cho' in obj_name: vType, val = self.getItemVal(item) if item == 'feedback': if val in ['Auditory', 'Both']: self.addItemScript('audio_output') self.items['audio_output'] = "added" else: self.removeItemScript('audio_output') __ = self.items.pop('audio_output', None) elif item == 'user_response': obj = wx.FindWindowByName("clickable_txt") if obj != None: if val == 'mouse_click': obj.SetEditable(True) obj.SetBackgroundColour('#ffffff') else: ### if user_response is not mouse_click, clickable should be all False ns = int( self.getItemVal("number_of_stimuli_per_trial")[1]) _v = str([False for x in range(ns)]) self.setItemVal("clickable", _v) obj.SetEditable(False) obj.SetBackgroundColour('#999999') self.parent.sPanel.updateItemVal(item) self.items[item] = val # store item's value if item == 'user_response' and val == 'key_stroke': msg = "For key_stroke to work, some programming is necessary.\n\nFirst, add desired keys to key_bindings.\ne.g.) To process key stroke of 'A' and 'L', add 'NONE+A, NONE+L' in key_bindings.\n\nNext, you should program how to deal with correct user response. The user response will be 'A' or 'L' in case of the above example. Which will be correct in which trial is determined in init_expmt function.\nMarkers for key_stroke related lines in the script will be shown after you close this window." show_msg(msg, size=(500, 300)) self.parent.sPanel.dispMarkers("key_stroke")