class DemoScreen(Screen): def __init__(self, disp, end_event, frame_getter): super(DemoScreen, self).__init__(disp) self.gaze = Circle(self.window, radius=50) self.gaze.fillColor = 'white' self.frame_getter = frame_getter self.min_time_over = False self.end_event = end_event def draw(self, debug_mode=False): frame = self.frame_getter() xy = (frame[u'avg'][u'x'], frame[u'avg'][u'y']) if xy == (0.0,0.0): xy = (-5000,-5000) self.gaze.pos = self.coords(xy) self.gaze.draw() if self.end_event.is_set(): self.move_on_flag.set() def cleanup(self): wait(0.5) for _ in range(50): self.gaze.setRadius(self.gaze.radius - 1) self.gaze.draw() self.window.flip()
class DemoScreen(Screen): """ A screen to allow participants to mess around with eye tracking while they wait for the other participants to finish instructions and calibration. """ def __init__(self, disp, end_event, frame_getter): super(DemoScreen, self).__init__(disp) self.gaze = Circle(self.window, radius=50) self.gaze.fillColor = 'white' self.frame_getter = frame_getter self.min_time_over = False self.end_event = end_event def draw(self, debug_mode=False): frame = self.frame_getter() xy = (frame[u'avg'][u'x'], frame[u'avg'][u'y']) if xy == (0.0, 0.0): xy = (-5000, -5000) self.gaze.pos = self.coords(xy) self.gaze.draw() if self.end_event.is_set(): self.move_on_flag.set() def cleanup(self): wait(0.5) for _ in range(50): self.gaze.setRadius(self.gaze.radius - 1) self.gaze.draw() self.window.flip()
def draw(self, location): y = 0 if location == "left": x = int(win_width * -0.25) left_targ = Circle(disp, pos=(x, y), radius=self.radius, edges=32, lineColor=self.color, fillColor=self.color) left_targ.draw() if location == "right": x = int(win_width * 0.25) right_targ = Circle(disp, pos=(x, y), radius=self.radius, edges=32, lineColor=self.color, fillColor=self.color) right_targ.draw()
class WaitScreen(EventInstructionsScreen): def __init__(self, disp, text, end_event): super(EventInstructionsScreen, self).__init__(disp, text) self.move_on_flag = end_event self.indicator = Circle(self.window, radius=10) self.mouse = Mouse() self.ticker = 0 self.ticker_unit = 2*pi/30 self.ticker_max = 2*pi self.indicator_dist = 15 def draw(self, debug_mode=False): self.instructions_text.draw() mouse_pos = self.mouse.getPos() x = mouse_pos[0] + self.indicator_dist*cos(self.ticker) y = mouse_pos[1] + self.indicator_dist*sin(self.ticker) self.indicator.pos = (x,y) self.indicator.draw() self.ticker += self.ticker_unit if self.ticker > self.ticker_max: self.ticker = 0
def draw_overview_target(win, level, target_pos, text_pos, mouse_clicks_all_levels): target = ImageStim(win, 'target.png', size=420, pos=target_pos) level_text = TextStim(win, text=f'Level {level}', height=35, color=(0.2, 0.2, 0.8), pos=text_pos) target.draw() level_text.draw() target_x, target_y = target_pos curr_level_mouse_clicks = mouse_clicks_all_levels[level - 1] for target_hit_pos in curr_level_mouse_clicks: if target_hit_pos['mouse_in_target']: circle = Circle(win, radius=5, fillColor='yellow', lineColor='yellow') circle.setPos((target_hit_pos['mouse_x'] + target_x, target_hit_pos['mouse_y'] + target_y)) circle.draw()
def main(): groups = create_stim_sequence(BLOCK1, BLOCK2, BLOCK3, TRIALREPEATS) print groups disp = Window(size=SIZE, monitor=MON, units='deg', color=BACKCOL, screen=1, fullscr=True) mouse = Mouse() fixmark = Circle(disp, radius=0.05, edges=32, pos=CENTER, lineColor=FIXCOL) images = [] for item in CIRCLES.keys(): image = ImageStim(disp, image=CIRCLES[item][1], pos=CIRCLES[item][0], size=CIRCLES[item][3]) images.append(image) fixmark.draw() draw_group(images) disp.flip() while True: button = mouse.getPressed() if button[0]: break for item in groups: flashes = [] for i in item: flash = ImageStim(disp, image=CIRCLES[i][2], pos=CIRCLES[i][0], size=CIRCLES[i][3]) flashes.append(flash) fixmark.draw() draw_group(images) draw_group(flashes) disp.flip() wait(FLASH) fixmark.draw() draw_group(images) wait(PAUSE) disp.flip() disp.close()
win, text= """Practice Block. \n\nUse the left mouse button to agree with the aid's decision or the right mouse button to disagree with the decision.""", wrapWidth=25, units='deg', pos=[0, 8], height=1, color='White') megchoice.draw() # Practice Block win.flip() waitKeys() win.mouseVisible = True megprac.draw() meg.draw() startButton.draw() win.flip() while myMouse.isPressedIn(startButton) == False: pass for trial in range(startPracticeTrials, endPracticeTrials): win.mouseVisible = False #Create the Aid's response (signal, autoResp, StimLength) = aidResponse(.15, .95) #easy, low FA wait(.5) #Trial begins with the onset of pointers trialStart = clock.getTime() myMouse.clickReset() background.draw() #Draw target targpos = [random.uniform(-1, 1), random.uniform(-1, 1)] target = Rect(win,
class DetectPupilsScreen(Screen): """ Screen which lets subjects see where they should move their head to get the best calibration. """ def __init__(self, disp, text, config_dict, pupil_coords_getter, seconds_to_ok): super(DetectPupilsScreen, self).__init__(disp) self.continue_button.pos = (0.0, 0.0) self.pupil_coords_getter = pupil_coords_getter cfg = config_dict[u'detect_pupils_screen'] self.in_range_ctr = 0 fps = self.window.getActualFrameRate() if fps is None: fps = 60 self.ctr_max = fps*seconds_to_ok self.detect_pupils_instructions = TextStim( self.window, text=text, pos=self.coords((self.x_cfg_2_pix(cfg[u'text'][u'x']), self.y_cfg_2_pix(cfg[u'text'][u'y']) )), wrapWidth=self.x_cfg_2_pix(cfg[u'text'][u'width']), height=cfg[u'text'][u'font_size'] ) self.lefteye = [] self.lefteye.append(Circle(self.window, radius=50)) self.lefteye[-1].fillColor = 'white' self.lefteye.append(Circle(self.window, radius=25)) self.lefteye[-1].fillColor = 'black' self.riteeye = [] self.riteeye.append(Circle(self.window, radius=50)) self.riteeye[-1].fillColor = 'white' self.riteeye.append(Circle(self.window, radius=25)) self.riteeye[-1].fillColor = 'black' # self.ok_indicator = RadialStim( # self.window, tex='none', mask='gauss', pos=(0,0), # size=(1000,1000), color=[0,0,0.5], opacity=0.5 # ) self.ok_indicator = Circle( self.window, radius=(350, 200), fillColor='palegreen', opacity=0.05, lineColor=None ) self.grid = [] for x, y in self.window.calib_points_coords: self.grid.append(Circle(self.window, radius=5, pos=self.coords((x, y)), lineColor=None, fillColor='green' )) def draw(self, debug_mode=False): ((leftx, lefty), (ritex, ritey)) = self.pupil_coords_getter() leftx *= self.window.hres lefty *= self.window.vres ritex *= self.window.hres ritey *= self.window.vres if leftx == 0.0 or lefty == 0.0: leftx, lefty = (-5000, -5000) if ritex == 0.0 or ritey == 0.0: ritex, ritey = (-5000, -5000) for circle in self.lefteye: circle.pos = self.coords((leftx, lefty)) for circle in self.riteeye: circle.pos = self.coords((ritex, ritey)) if self.ok_indicator.contains(self.lefteye[0].pos) and self.ok_indicator.contains(self.riteeye[0].pos): self.in_range_ctr += 1 op = self.ok_indicator.opacity + 0.03 self.ok_indicator.opacity = min(op, 0.65) else: op = self.ok_indicator.opacity - 0.03 self.ok_indicator.opacity = max(op, 0.05) if (self.in_range_ctr >= self.ctr_max) or debug_mode: self.continue_button.clickable = True # draw commands for thing in self.grid: thing.draw() self.ok_indicator.draw() self.detect_pupils_instructions.draw() self.continue_button.draw() for circle in self.lefteye: circle.draw() for circle in self.riteeye: circle.draw()
class ContribScreen(Screen): """ This screen lets users select their contribution. """ def __init__(self, disp, text, config_dict, gaze_pos_getter=None, width=None, height=None, margin=None, font_size=None, choice_font_size=100, origin=None ): super(ContribScreen, self).__init__(disp) cfg = config_dict[u'contrib_screen'] self.gaze_pos_getter = gaze_pos_getter self.instr_text_preformat = text self.contrib_choice = '__' self.mouseover_threshold = 0 self.choice_coords = [] if width is not None: self.width = width else: self.width = self.window.hres if height is not None: self.height = height else: self.height = self.window.vres if margin is not None: self.margin = margin else: self.margin = self.window.margin if origin is not None: self.origin = origin if font_size is None: font_size = config_dict[u'contrib_screen'][u'text'][u'font_size'] self.contrib_choices = self.gen_contrib_choices( cfg[u'nrows'], cfg[u'ncols'], font_size=choice_font_size ) self.contrib_instructions = TextStim( self.window, height=font_size, text=self.instr_text_preformat.format(self.contrib_choice), pos=self.coords((self.x_cfg_2_pix(cfg[u'text'][u'x']), self.y_cfg_2_pix(cfg[u'text'][u'y']) )), wrapWidth=self.w_cfg_2_pix(cfg[u'text'][u'width']) ) self.gaze = Circle(self.window, radius=5) self.gaze.fillColor = 'red' def draw(self, debug_mode=False): mouse_x, mouse_y = self.mouse.getPos() for text_stim in self.contrib_choices: if xydist((mouse_x, mouse_y), text_stim.pos) < self.mouseover_threshold: text_stim.color = 'darkorange' if self.mouse.getPressed()[0]: self.contrib_choice = text_stim.text self.contrib_instructions.setText(self.instr_text_preformat.format(self.contrib_choice)) self.continue_button.clickable = True else: text_stim.color = 'white' text_stim.draw() self.continue_button.draw() self.contrib_instructions.draw() if self.gaze_pos_getter is not None: self.gaze.pos = self.coords(self.gaze_pos_getter()) self.gaze.draw() def cleanup(self): self.continue_button.clickable = False self.contrib_instructions.setText(self.instr_text_preformat.format('__')) self.move_on_flag.clear() def gen_contrib_choices(self, nrows, ncols, font_size): h_spacing = (self.width - 2*self.margin)/(ncols-1) v_spacing = h_spacing '''OR: v_spacing = (self.height - 2*self.margin)/(nrows-1)''' self.mouseover_threshold = min(h_spacing, v_spacing)/4 contrib_choices = [] for i in range(0, nrows*ncols): xpos = self.margin + (i % ncols)*h_spacing ''' To move the array to the bottom of the page: ypos = self.height - self.margin - (nrows-floor(1.0*i/ncols)-1)*v_spacing ''' ypos = floor(1.0*i/ncols)*v_spacing + self.margin ''' 1.0*i/ncols gives us a floating-point number. Without the 1.0, python interprets this as int-division and truncates. I could have exploited this for slightly simpler code but it is really stupid that it works that way and who knows what bugs could pop up by relying on something that is in my opinion a bug? We take the floor of that number to give us a "row index." We multiply this number by the vertical spacing. ''' if i < 10: temp = ' {} '.format(i) else: temp = '{}'.format(i) contrib_choices.append(TextStim(win=self.window, text=temp, pos=self.coords((xpos, ypos)), height=font_size)) self.choice_coords.append((xpos, ypos)) return contrib_choices
class DetectPupilsScreen(Screen): def __init__(self, disp, text, config_dict, pupil_coords_getter, seconds_to_ok): super(DetectPupilsScreen, self).__init__(disp) self.continue_button.setPos((0.0,0.0)) self.pupil_coords_getter = pupil_coords_getter cfg = config_dict[u'detect_pupils_screen'] self.in_range_ctr = 0 fps = self.window.getActualFrameRate() self.ctr_max = fps*seconds_to_ok self.detect_pupils_instructions = TextStim( self.window, text=text, pos=self.coords((self.x_cfg_2_pix(cfg[u'text'][u'x']), self.y_cfg_2_pix(cfg[u'text'][u'y']) )), wrapWidth=self.x_cfg_2_pix(cfg[u'text'][u'width']), height=cfg[u'text'][u'font_size'] ) self.lefteye = [] self.lefteye.append(Circle(self.window, radius=50)) self.lefteye[-1].fillColor='white' self.lefteye.append(Circle(self.window, radius=25)) self.lefteye[-1].fillColor='black' self.riteeye = [] self.riteeye.append(Circle(self.window, radius=50)) self.riteeye[-1].fillColor='white' self.riteeye.append(Circle(self.window, radius=25)) self.riteeye[-1].fillColor='black' # self.ok_indicator = RadialStim( # self.window, tex='none', mask='gauss', pos=(0,0), # size=(1000,1000), color=[0,0,0.5], opacity=0.5 # ) self.ok_indicator = Circle( self.window, radius=(350,200), fillColor='palegreen', opacity=0.05, lineColor=None ) self.grid = [] for x, y in self.window.calib_points_coords: self.grid.append(Circle(self.window, radius=5, pos=self.coords((x, y)), lineColor=None, fillColor='green' )) def draw(self, debug_mode=False): ((leftx,lefty),(ritex,ritey)) = self.pupil_coords_getter() leftx *= self.window.hres lefty *= self.window.vres ritex *= self.window.hres ritey *= self.window.vres if leftx == 0.0 or lefty == 0.0: leftx, lefty = (-5000,-5000) if ritex == 0.0 or ritey == 0.0: ritex, ritey = (-5000,-5000) for circle in self.lefteye: circle.pos = self.coords((leftx,lefty)) for circle in self.riteeye: circle.pos = self.coords((ritex,ritey)) # ldist = xydist([leftx,lefty], (self.window.hres/2,self.window.vres/2)) # rdist = xydist([ritex,ritey], (self.window.hres/2,self.window.vres/2)) # if ldist+rdist < self.window.vres/2: # self.in_range_ctr += 1 if (self.ok_indicator.contains(self.lefteye[0].pos) and self.ok_indicator.contains(self.riteeye[0].pos) ): self.in_range_ctr += 1 op = self.ok_indicator.opacity + 0.03 self.ok_indicator.opacity = min(op, 0.65) else: op = self.ok_indicator.opacity - 0.03 self.ok_indicator.opacity = max(op, 0.05) # # # if missed_flag: # temp = self.ok_indicator.color * 0.95 # temp[2] = 0.5 # temp[0] = 0 # else: # ratio = self.window.vres/(3*(ldist+rdist)) # if ratio > 1: # ratio = 1 # temp = [0, ratio, 0.5] # # self.ok_indicator.color = temp if ((self.in_range_ctr >= self.ctr_max) or debug_mode ): self.continue_button.clickable = True # draw commands for thing in self.grid: thing.draw() self.ok_indicator.draw() self.detect_pupils_instructions.draw() self.continue_button.draw() for circle in self.lefteye: circle.draw() for circle in self.riteeye: circle.draw()
class FeedbackScreen(Screen): # This should not be messed with, we want to maintain between- # subject counterbalancing, but not change things within-subject. reversed = choice([True, False]) def __init__(self, disp, num_players, config_dict, gaze_pos_getter=None, width=None, height=None, margin=None, font_size=None, col_x_list=[], AOIs=False): super(FeedbackScreen, self).__init__(disp) self.gaze_pos_getter = gaze_pos_getter self.continue_button.clickable = True cfg = config_dict[u'feedback_screen'] if width is not None: self.width = width else: self.width = self.window.hres if height is not None: self.height = height else: self.height = self.window.vres if margin is not None: self.margin = margin else: self.margin = self.window.margin if font_size is not None: self.font_size = font_size else: self.font_size = config_dict[u'feedback_screen'][u'font_size'] self.col_x_list = [] if col_x_list == []: self.col_x_list.append( self.x_cfg_2_pix( config_dict[u'feedback_screen'][u'left_col_x'] )) self.col_x_list.append( self.x_cfg_2_pix( config_dict[u'feedback_screen'][u'midd_col_x'] )) self.col_x_list.append( self.x_cfg_2_pix( config_dict[u'feedback_screen'][u'rite_col_x'] )) del col_x_list if FeedbackScreen.reversed: self.col_x_list.reverse() self.gaze = Circle(self.window, radius=5) self.gaze.fillColor = 'red' self.nrows = num_players + 3 self.SUMROWINDEX = self.nrows - 2 self.AVGROWINDEX = self.nrows - 1 row_spacing = (self.height - 2*self.margin)/(self.nrows-1) self.contr_col = [] self.label_col = [] self.payof_col = [] for i in range(self.nrows): y = self.window.margin + i*row_spacing temp_contr = TextStim(self.window, height=self.font_size) temp_label = TextStim(self.window, height=self.font_size) temp_payof = TextStim(self.window, height=self.font_size) if i == 0: temp_contr.setText(cfg[u'contributions']) temp_label.setText(cfg[u'players']) temp_payof.setText(cfg[u'payoffs']) else: temp_contr.setText('xx') temp_payof.setText('xx') if i == 1: temp_label.setText(cfg[u'you']) elif i <= num_players: temp_label.setText(cfg[u'others'][i-2]) elif i == self.SUMROWINDEX: temp_label.setText(cfg[u'sum']) elif i == self.AVGROWINDEX: temp_label.setText(cfg[u'average']) else: logging.error('Error in FeedbackScreen.__init__(). Wrong number of rows?') temp_contr.setPos(self.coords((self.col_x_list[0], y))) self.contr_col.append(temp_contr) temp_label.setPos(self.coords((self.col_x_list[1], y))) self.label_col.append(temp_label) temp_payof.setPos(self.coords((self.col_x_list[2], y))) self.payof_col.append(temp_payof) self.AOIs = [] if AOIs: for _ in range(3): self.AOIs.append(Rect(self.window, width=400, height=280, lineColor='slateblue', fillColor='steelblue')) self.AOIs[-1].setPos(self.contr_col[-1].pos) self.AOIs[-2].setPos(self.label_col[-1].pos) self.AOIs[-3].setPos(self.payof_col[-1].pos) def draw(self, debug_mode=False): if getAbsTime() - self.t0 > 30: self.move_on_flag.set() if self.AOIs != [] and self.gaze_pos_getter is not None: self.gaze.pos = self.coords(self.gaze_pos_getter()) for shape in self.AOIs: if shape.contains(self.gaze.pos): shape.setFillColor('slateblue') else: shape.setFillColor('steelblue') for shape in self.AOIs: shape.draw() self.gaze.draw() for i in range(self.nrows): self.label_col[i].draw() self.contr_col[i].draw() self.payof_col[i].draw() self.continue_button.draw() def cleanup(self): self.move_on_flag.clear() def update_info(self, contr_avg, payoff_avg, contr_sum, payoff_sum, my_contr, my_payoff, other_contr=[], other_payoff=[]): # This bit randomizes the order that the other players are # presented in on the feedback screen. Not yet tested to # make sure it works, but it should. Only matters if N > 2. # if len(other_contr) > 1: # indices = [] # for i in range(len(other_contr)): # indices.append(i) # shuffle(indices) # temp_contr = other_contr[:] # temp_payoff = other_payoff[:] # for i in range(len(indices)): # other_contr[i] = temp_contr[indices[i]] # other_payoff[i] = temp_payoff[indices[i]] self.update_col(self.contr_col, contr_avg, contr_sum, my_contr, other_contr) self.update_col(self.payof_col, payoff_avg, payoff_sum, my_payoff, other_payoff) def update_col(self, col, avg, sum_, mine, others): # avg = str(avg).replace('.',',') avg = '{:n}'.format(avg) sum_ = '{:n}'.format(sum_) mine = '{:n}'.format(mine) col[self.AVGROWINDEX].setText(avg) col[self.SUMROWINDEX].setText(sum_) col[1].setText(mine) for i in range(len(others)): other = '{:n}'.format(others[i]) col[i+2].setText(other)
class CalibratableWindow(Window): def __init__(self, num_calib_points=9, margin=100, **kwargs ): super(CalibratableWindow, self).__init__( **kwargs ) self.hres = int(self.size[0]) self.vres = int(self.size[1]) self.num_calib_points = num_calib_points self.margin = margin self.calib_points_coords = self.gen_calib_point_coords() def calibrate(self, et_comm): self.setMouseVisible(False) self.make_points() start_reply = et_comm.start_calibration(self.num_calib_points) if start_reply[u'statuscode'] == 403: et_comm.abort_calibration() et_comm.start_calibration(self.num_calib_points) calibration_obj={} for x,y in self.calib_points_coords: self.point_place(x,y) wait(0.750) et_comm.start_calib_point(x,y) self.point_expand_contract(duration=1) calibration_obj = et_comm.end_calib_point() wait(0.250) self.setMouseVisible(True) return calibration_obj[u'values'][u'calibresult'] def make_points(self): self.outer_point = Circle(self, radius=25) self.outer_point.fillColor = 'white' self.outer_point.setPos((5000,5000)) self.inner_point = Circle(self, radius=5) self.inner_point.fillColor = 'red' self.inner_point.setPos((5000,5000)) def point_place(self, x, y): xy_tuple = self.tl2c((x,y)) self.outer_point.setPos(xy_tuple) self.inner_point.setPos(xy_tuple) self.outer_point.draw() self.inner_point.draw() self.flip() def tl2c(self, coords_tuple): x = coords_tuple[0] - self.hres/2 y = coords_tuple[1] - self.vres/2 return (x, -y) def point_expand_contract(self, duration): start_time = getTime() ratio = 0 while ratio < 1: ratio = (getTime()-start_time)/(duration*0.5) self.outer_point.setRadius(25+25*ratio) self.outer_point.draw() self.inner_point.draw() self.flip() while ratio < 2: ratio = (getTime()-start_time)/(duration*0.5) self.outer_point.setRadius(75-25*ratio) self.outer_point.draw() self.inner_point.draw() self.flip() def gen_calib_point_coords(self): if self.num_calib_points == 9: nrows = 3 ncols = 3 elif self.num_calib_points == 12: nrows = 3 ncols = 4 elif self.num_calib_points == 16: nrows = 4 ncols = 4 else: print('Unacceptable number of calibration points. ' 'Please choose 9, 12, or 16. Defaulting to 9.') nrows = 3 ncols = 3 coord_list = [] h_spacing = (self.hres - 2*self.margin)/(ncols-1) v_spacing = (self.vres - 2*self.margin)/(nrows-1) for row in range(nrows): for col in range(ncols): coord_list.append((col*h_spacing + self.margin, row*v_spacing + self.margin)) shuffle(coord_list) return coord_list
# feedback screens fbstim = {} fbstim[0] = TextStim(disp, text='Incorrect', height=24, color=(1, 1, -1)) fbstim[1] = TextStim(disp, text='Correct', height=24, color=(-1, 1, -1)) # present instructions inststim.draw() disp.flip() waitKeys(maxWait=float('inf'), keyList=None, timeStamped=True) # wait for key press for cueside in ['left', "right"]: # draw fixation mark and left and right boxes fixstim.draw() lboxstim.draw() rboxstim.draw() fixonset = disp.flip() wait(FIXTIME) fixstim.draw() lboxstim.draw() rboxstim.draw() cuestim[cueside].draw() cueonset = disp.flip() wait(CUETIME) fixstim.draw() lboxstim.draw() rboxstim.draw() cueoffset = disp.flip()
class PsychopyCustomDisplay(pylink.EyeLinkCustomDisplay): """ Custom display for Eyelink eyetracker. Modified from the 'pylinkwrapper' package by Nick DiQuattro (https://github.com/ndiquattro/pylinkwrapper). All credits go to him. """ def __init__(self, tracker, win, settings): """ Initializes PsychopyCustomDisplay object. """ super().__init__() self.tracker = tracker self.win = win self.settings = settings # from session self.txtcol = -1 #self.__target_beep__ = sound.Sound(800, secs=.1) # THIS WILL GIVE A SEGFAULT! #self.__target_beep__done__ = sound.Sound(1200, secs=.1) # THIS WILL GIVE A SEGFAULT! #self.__target_beep__error__ = sound.Sound(400, secs=.1) # THIS WILL GIVE A SEGFAULT! self.backcolor = self.win.color dot_size_pix = misc.deg2pix( self.settings['eyetracker'].get('dot_size'), self.win.monitor) self.targetout = Circle(self.win, pos=(0, 0), radius=dot_size_pix, fillColor='black', units='pix', lineColor='black') self.targetin = Circle(self.win, pos=(0, 0), radius=3, fillColor=0, lineColor=0, units='pix', opacity=0) win.flip() def setup_cal_display(self): txt = TextStim( self.win, text= "Please follow the dot. Try not to anticipate its movements.", pos=(0, 100), color='black', units='pix') txt.draw() self.targetout.draw() self.win.flip() def exit_cal_display(self): self.clear_cal_display() def clear_cal_display(self): self.setup_cal_display() def erase_cal_target(self): self.win.flip() def draw_cal_target(self, x, y): # Convert to psychopy coordinates x = x - (self.win.size[0] / 2) y = -(y - (self.win.size[1] / 2)) # Set calibration target position self.targetout.pos = (x, y) self.targetin.pos = (x, y) # Display self.targetout.draw() self.targetin.draw() self.win.flip() def alert_printf(self, msg): print("alert_printf %s" % msg) def play_beep(self, beepid): if beepid == pylink.DC_TARG_BEEP or beepid == pylink.CAL_TARG_BEEP: self.__target_beep__.play() elif beepid == pylink.CAL_ERR_BEEP or beepid == pylink.DC_ERR_BEEP: self.__target_beep__error__.play() else: # CAL_GOOD_BEEP or DC_GOOD_BEEP self.__target_beep__done__.play() def get_input_key(self): ky = [] v = event.getKeys() for key in v: pylink_key = None if len(key) == 1: pylink_key = ord(key) elif key == "escape": pylink_key = pylink.ESC_KEY elif key == "return": pylink_key = pylink.ENTER_KEY elif key == "pageup": pylink_key = pylink.PAGE_UP elif key == "pagedown": pylink_key = pylink.PAGE_DOWN elif key == "up": pylink_key = pylink.CURS_UP elif key == "down": pylink_key = pylink.CURS_DOWN elif key == "left": pylink_key = pylink.CURS_LEFT elif key == "right": pylink_key = pylink.CURS_RIGHT else: print(f'Error! :{key} is not a used key.') return ky.append(pylink.KeyInput(pylink_key, 0)) return ky def record_abort_hide(self): pass def setup_image_display(self, width, height): self.size = (width / 2, height / 2) self.clear_cal_display() self.last_mouse_state = -1 # Create array to hold image data later if self.rgb_index_array is None: self.rgb_index_array = np.zeros((self.size[1], self.size[0]), dtype=np.uint8) def exit_image_display(self): self.clear_cal_display() def image_title(self, text): # Display or update Pupil/CR info on image screen if self.imagetitlestim is None: self.imagetitlestim = TextStim( self.window, text=text, pos=(0, self.window.size[1] / 2 - 15), height=28, color=self.txtcol, alignHoriz='center', alignVert='top', wrapWidth=self.window.size[0] * .8, units='pix') else: self.imagetitlestim.setText(text) def exit_image_display(self): self.clear_cal_display() def draw_image_line(self, width, line, totlines, buff): # Get image info for each line of image for i in range(width): self.rgb_index_array[line - 1, i] = buff[i] # Once all lines are collected turn into an image to display if line == totlines: # Make image image = scipy.misc.toimage(self.rgb_index_array, pal=self.rgb_pallete, mode='P') # Resize Image if self.imgstim_size is None: maxsz = self.sres[0] / 2 mx = 1.0 while (mx + 1) * self.size[0] <= maxsz: mx += 1.0 self.imgstim_size = int(self.size[0] * mx), int( self.size[1] * mx) image = image.resize(self.imgstim_size) # Save image as a temporay file tfile = os.path.join(tempfile.gettempdir(), '_eleye.png') image.save(tfile, 'PNG') # Need this for target distance to show up self.__img__ = image self.draw_cross_hair() self.__img__ = None # Create eye image if self.eye_image is None: self.eye_image = visual.ImageStim(self.window, tfile, size=self.imgstim_size, units='pix') else: self.eye_image.setImage(tfile) # Redraw the Camera Setup Mode graphics self.eye_image.draw() if self.imagetitlestim: self.imagetitlestim.draw() # Display self.window.flip() def set_image_palette(self, r, g, b): # This does something the other image functions need self.clear_cal_display() sz = len(r) self.rgb_pallete = np.zeros((sz, 3), dtype=np.uint8) i = 0 while i < sz: self.rgb_pallete[i:] = int(r[i]), int(g[i]), int(b[i]) i += 1 def dummynote(self): # Draw Text visual.TextStim(self.window, text='Dummy Connection with EyeLink', color=self.txtcol).draw() self.window.flip() # Wait for key press event.waitKeys() self.window.flip()