def _ParallelWithPrevious(name=None, parallel_name=None, blocking=True): # get the exp reference from experiment import Experiment try: exp = Experiment._last_instance() except AttributeError: raise StateConstructionError( "You must first instantiate an Experiment.") # find the parent parent = exp._parents[-1] # find the previous child state (-1 because this is not a state) try: prev_state = parent._children[-1] parallel_parent = parent except IndexError: prev_state = parent if parent._parent is None: parallel_parent = parent._exp else: parallel_parent = parent._parent # build the new Parallel state with Parallel(name=parallel_name, parent=parallel_parent, blocking=blocking) as p: p.override_instantiation_context(3) p.claim_child(prev_state) with Serial(name=name) as s: s.override_instantiation_context(3) yield p
def MousePos(widget=None): pos = Experiment._last_instance()._app.mouse_pos_ref if widget is None: return pos else: return Ref.cond(MouseWithin(widget), Ref(map, operator.sub, pos, widget.pos), None)
def Else(name="ELSE BODY"): """State to attach to the else of an If state. """ # get the exp reference from experiment import Experiment try: exp = Experiment._last_instance() except AttributeError: raise StateConstructionError( "You must first instantiate an Experiment.") # find the parent parent = exp._parents[-1] # find the previous child state (-1 because this is not a state) try: prev_state = parent._children[-1] except IndexError: raise StateConstructionError("No previous state for Else.") # make sure it's the If if not isinstance(prev_state, If): raise StateConstructionError( "The previous state must be an If or Elif state.") # return the false_state (the last out_state) false_state = prev_state._out_states[-1] false_state._name = name false_state.override_instantiation_context() return false_state
def MouseButton(widget=None): """Returns a Reference to the next mouse button to be pressed. If given a widget, it will only return the mouse button pressed if it was pressed while the mouse was within the widget. If not given a widget, it will return a reference to the next button to be pressed on the mouse. """ button = Experiment._last_instance()._app.mouse_button_ref if widget is None: return button else: return Ref.cond(MouseWithin(widget), button, None)
def Key(name): """Acceptable Keys ['A','B','C','D','E','F','G','H','I','J','K', 'L','M','N','O','P','Q','R','S','T','U','V', 'W','X','Y','Z','0','1','2','3','4','5','6', '7','8','9','LSHIFT','RSHIFT','SPACEBAR','ENTER', 'LCTRL','RCTRL','ESC'] """ exp = Experiment._last_instance() return exp.screen._get_key_ref(name.upper())
def MousePos(widget=None): """Returns the position of the mouse. If given a widget, this function will return the position of the mouse in reference to the position of the widget. If widget is set to None, then this function will return the mouse position in relation to the experiment window. """ pos = Experiment._last_instance()._app.mouse_pos_ref if widget is None: return pos else: return Ref.cond(MouseWithin(widget), Ref(map, operator.sub, pos, widget.pos), None)
def MouseButton(widget=None): """Returns a Reference to the next mouse button to be pressed. If given a widget, it will only return the mouse button pressed if it was pressed while the mouse was within the widget. If not given a widget, it will return a reference to the next button to be pressed on the mouse. """ button = Experiment._last_instance().screen.mouse_button if widget is None: return button else: return Ref.cond(MouseWithin(widget), button, None)
def MousePos(widget=None): """Returns the position of the mouse. If given a widget, this function will return the position of the mouse in reference to the position of the widget. If widget is set to None, then this function will return the mouse position in relation to the experiment window. """ pos = Experiment._last_instance().screen.mouse_pos if widget is None: return pos else: return Ref.cond(MouseWithin(widget), Ref(map, operator.sub, pos, widget.pos), None)
def enter(self, start_time): self.claim_exceptions() self._start_time = start_time self._enter_time = clock.now() self._leave_time = None self._finalize_time = None self.__original_state.__most_recently_entered_clone = self # say we're active self._active = True self._following_may_run = False if self._parent: clock.schedule(partial(self._parent.child_enter_callback, self)) # if we don't have the exp reference, get it now if self._exp is None: from experiment import Experiment self._exp = Experiment._last_instance() for name, value in self.__dict__.items(): if name[:6] == "_init_": setattr(self, name[5:], val(value)) if self._duration is None: self._end_time = None else: self._end_time = self._start_time + self._duration # custom enter code self._enter() if self.__tracing: call_time = self._enter_time - self._exp._root_state._start_time call_duration = clock.now() - self._enter_time start_time = self._start_time - self._exp._root_state._start_time self.print_trace_msg( "ENTER time=%fs, duration=%fs, start_time=%fs" % (call_time, call_duration, start_time))
def MouseWithin(widget): print 'MouseWithin' """An easy shortcut to wait for a mouse to be within a widget. This function returns True if the mouse position is within a given widget. When used in conjunction with the *Wait* state, it can wait until the mouse is within a widget. Parameters ---------- widget : Kivy Widget (Any WidgetState) This parameter is whatever widget you would like to check and see if the mouse is within it. Example ------- :: rec = Rectangle(height=10, width=10, color='RED') with UntilDone(): with Parallel(): MouseCursor(duration=10) with Serial(): Wait(until=MouseWithin(rec)) Label(text='You got the cursor into the square!', color='GREEN', center_y=exp.screen.center_y/2, duration=5) This example will draw a rectangle and wait until you put the cursor within the rectangle. Once that happens, a *Label* will appear telling the participant that they did the correct thing. """ pos = Experiment._last_instance().screen.mouse_pos return ((pos[0] >= widget.x) & (pos[1] >= widget.y) & (pos[0] <= widget.right) & (pos[1] <= widget.top))
def MouseWithin(widget): """An easy shortcut to wait for a mouse to be within a widget. This function returns True if the mouse position is within a given widget. When used in conjunction with the *Wait* state, it can wait until the mouse is within a widget. Parameters ---------- widget : Kivy Widget (Any WidgetState) This parameter is whatever widget you would like to check and see if the mouse is within it. Example ------- :: rec = Rectangle(height=10, width=10, color='RED') with UntilDone(): with Parallel(): MouseCursor(duration=10) with Serial(): Wait(until=MouseWithin(rec)) Label(text='You got the cursor into the square!', color='GREEN', center_y=exp.screen.center_y/2, duration=5) This example will draw a rectangle and wait until you put the cursor within the rectangle. Once that happens, a *Label* will appear telling the participant that they did the correct thing. """ pos = Experiment._last_instance().screen.mouse_pos return ((pos[0] >= widget.x) & (pos[1] >= widget.y) & (pos[0] <= widget.right) & (pos[1] <= widget.top))
def MouseButton(widget=None): button = Experiment._last_instance()._app.mouse_button_ref if widget is None: return button else: return Ref.cond(MouseWithin(widget), button, None)
def Key(name): exp = Experiment._last_instance() return exp._app.get_key_ref(name.upper())
def MouseWithin(widget): pos = Experiment._last_instance()._app.mouse_pos_ref return (pos[0] >= widget.x & pos[1] >= widget.y & pos[0] <= widget.right & pos[1] <= widget.top)
def __init__(self, parent=None, duration=None, save_log=True, name=None, blocking=True): # Weak value dictionary to track Refs issued by this state. Necessary # because those Refs need to be notified when their dependencies # change. This is first so that __setattr__ will work. self.__issued_refs = weakref.WeakValueDictionary() # If true, we write a log entry every time this state finalizes. self.__save_log = save_log # The custom name for this state. self._name = name # Whether or not this state blocks in the context of a Parallel parent. self._blocking = blocking # This is a convenience argument for automatically setting the end time # relative to the start time. If it evaluates to None, it has no # effect. self._init_duration = duration # Start and end time for the state. Start time is set at enter time. # End time must be set before leave time. End time will be set # automatically at enter time if a duration is provided. self._start_time = None self._end_time = None # Record of enter time, leave time, and finalize time at and after the # most recent enter. self._enter_time = None self._leave_time = None self._finalize_time = None # This flag is set True at enter time and False at finalize time. It # indicates that it is not safe to enter this instance for a new # execution of the state. If the instance is active a new clone of the # state can be constructed and that one entered instead. self._active = False # This flag is set False at enter time and True at leave time. # It indicates that it is safe for subsequent states in a series to # enter. self._following_may_run = False # This indicates the correct indentation level for this state in trace # output. self.__depth = 0 # This flag indicates that trace output should be generated. self.__tracing = False # Record which source file and line number this constructor was called # from. self.set_instantiation_context() # Associate this state with the most recently instantiated Experiment. from experiment import Experiment try: self._exp = Experiment._last_instance() except AttributeError: self._exp = None # Determine the parent for this state... if parent is None: if self._exp is None: # If there is no explicit parent and no associated experiment, # set parent to None. self._parent = None else: # If there is not explicit parent, use the state at the top of # the associated experiment's parent stack. self._parent = self._exp._parents[-1] elif parent is self._exp: # If the associated experment is passed in as the parent, set this # state as the associated experiment's root state. self._parent = None self._exp._root_state = self else: self._parent = parent # Raise an error if we are non-blocking, but not the child of a # Parallel... #TODO: check this any time self._blocking is assigned! if not self._blocking and not isinstance(self._parent, Parallel): raise StateConstructionError( "A state which is not a child of a Parallel cannot be " "non-blocking.") # If this state has a parent, add this state to its parent's children. if self._parent: self._parent._children.append(self) # These are the names of attributes (minus leading underscores) which # will be logged at finalization time. Subclasses should extend this # list to cause additional attributes to be logged. self._log_attrs = ['instantiation_filename', 'instantiation_lineno', 'name', 'start_time', 'end_time', 'enter_time', 'leave_time', 'finalize_time'] # Concerning state cloning... # List of attributes that should be deep copied during cloning. # Subclasses should extend this list as needed. self._deepcopy_attrs = [] # This will allows be the originally constructed state, even in cloned # copies. self.__original_state = self # This is only valid in the original state. It is the most recent # clone of the state (which could be the original itself) to have been # entered. This is used to seemlessly evaluate Refs to values from the # most recently started execution of a state. self.__most_recently_entered_clone = self