示例#1
0
 def _updateVertices(self):
     """
     """
     #then combine with position and convert to pix
     pos = convertToPix(vertices = [0,0], pos = self.pos, units=self.units, win=self.win)
     size = convertToPix(vertices = self.size, pos = 0, units=self.units, win=self.win)
     try:
         size=size[0]
     except:
         pass
     #assign to self attrbute
     self.__dict__['posPix'] = pos
     self.__dict__['sizePix'] = size
     self._needVertexUpdate = False
示例#2
0
    def _updateVertices(self):
        """Sets Stim.verticesPix from fieldPos and
        """

        #Handle the orientation, size and location of each element in native units
        #
        radians = 0.017453292519943295
        verts = numpy.zeros([self.nElements*4, 3],'d')
        #rotate 'width' and 'height' and find their effects on X and Y
        wx = -self.sizes[:,0]*numpy.cos(self.oris[:]*radians)/2
        wy = self.sizes[:,0]*numpy.sin(self.oris[:]*radians)/2
        hx = self.sizes[:,1]*numpy.sin(self.oris[:]*radians)/2
        hy = self.sizes[:,1]*numpy.cos(self.oris[:]*radians)/2
        #X
        verts[0::4,0] = + wx + hx#TopR
        verts[1::4,0] = - wx + hx#TopL
        verts[2::4,0] = - wx - hx#BotL
        verts[3::4,0] = + wx - hx#BotR
        #Y
        verts[0::4,1] = + wy + hy
        verts[1::4,1] = - wy + hy
        verts[2::4,1] = - wy - hy
        verts[3::4,1] = + wy - hy
        #Z
        verts[:,2] = 1#self.depths + self.fieldDepth
        #Now shift by fieldPos and convert to appropriate units
        pos = numpy.tile(self.xys+self.fieldPos, (1,4)).reshape([self.nElements*4,2])
        verts[:,:2] = convertToPix(vertices = verts[:,:2], pos = pos, units=self.units, win = self.win)
        #assign to self attrbute
        self.__dict__['verticesPix'] = numpy.require(verts,requirements=['C'])#make sure it's contiguous
        self._needVertexUpdate = False
示例#3
0
    def height(self, height):
        """The height of the letters (Float/int or None = set default).

        Height includes the entire box that surrounds the letters
        in the font. The width of the letters is then defined by the font.

        :ref:`Operations <attrib-operations>` supported."""
        # height in pix (needs to be done after units which is done during
        # _Base.__init__)
        if height is None:
            if self.units in defaultLetterHeight:
                height = defaultLetterHeight[self.units]
            else:
                msg = ("TextStim does now know a default letter height "
                       "for units %s")
                raise AttributeError(msg % repr(self.units))
        self.__dict__['height'] = height
        self._heightPix = convertToPix(pos=numpy.array([0, 0]),
                                       vertices=numpy.array([0, self.height]),
                                       units=self.units,
                                       win=self.win)[1]

        # need to update the font to reflect the change
        self.setFont(self.font, log=False)
        return self.__dict__['height']
示例#4
0
    def _move_cursor(self, mouse, t_remain, cursor_t):
        """ Method for adjusting the position of the cursor and drawing the
        trace. Wrote mainly to aid profiling."""

        new_trace = False
        # Get new position from mouse
        if mouse.getPressed()[0]:
            if self.frame['lifted']:
                new_trace = True
                self.frame['start_frame_idx'] = self.frame['idx'] + 1
            self.frame['lifted'] = False
            new_pos = convertToPix(mouse.getPos(), (0, 0), units=mouse.units,
                                   win=self.win)
        else:

            self.frame['lifted'] = True
            new_pos = self.frame['trace_vertices'][self.frame['idx']]

        # Record time at which that happened
        # cursor_t.append(t_remain)
        cursor_t[self.frame['idx']] = t_remain

        # Move cursor to that position and save
        self.frame['elements']['cursor'].pos = new_pos

        # For drawing trace
        self._draw_trace(new_pos, new_trace=new_trace)
示例#5
0
    def vertices(self):
        textbox = self.textbox
        # check we have a caret index
        if self.index is None or self.index > len(textbox.text):
            self.index = len(textbox.text)
        if self.index < 0:
            self.index = 0
        # get the verts of character next to caret (chr is the next one so use
        # left edge unless last index then use the right of prev chr)
        # lastChar = [bottLeft, topLeft, **bottRight**, **topRight**]
        ii = self.index
        if textbox.vertices.shape[0] == 0:
            verts = self.textbox._getStartingVertices()
            verts[:,1] = verts[:,1] / float(textbox._pixelScaling)
            verts[:,1] = verts[:,1] + float(textbox._anchorOffsetY)
        else:
            if self.index >= len(textbox._lineNs):  # caret is after last chr
                chrVerts = textbox.vertices[range((ii-1) * 4, (ii-1) * 4 + 4)]
                x = chrVerts[2, 0]  # x-coord of left edge (of final char)
            else:
                chrVerts = textbox.vertices[range(ii * 4, ii * 4 + 4)]
                x = chrVerts[1, 0]  # x-coord of right edge
            # the y locations are the top and bottom of this line
            y1 = textbox._lineBottoms[self.row] / textbox._pixelScaling
            y2 = textbox._lineTops[self.row] / textbox._pixelScaling
            # char x pos has been corrected for anchor already but lines haven't
            verts = (np.array([[x, y1], [x, y2]])
                     + (0, textbox._anchorOffsetY))

        return convertToPix(vertices=verts, pos=textbox.pos,
                            win=textbox.win, units=textbox.units)
示例#6
0
    def _caretVertices(self):
        # check we have a caret index
        if self.caretIndex is None or self.caretIndex > len(self._lineNs):
            self.caretIndex = len(self.text)
        # get the verts of character next to caret (chr is the next one so use
        # left edge unless last index then use the right of prev chr)
        # lastChar = [bottLeft, topLeft, **bottRight**, **topRight**]
        if self.caretIndex >= len(self.text):  # caret is after last chr
            chrVerts = self._index2vertices(self.caretIndex - 1)
            lineN = self._lineNs[self.caretIndex - 1]
            x = chrVerts[2, 0]  # x-coord of right edge (of final char)
        else:
            chrVerts = self._index2vertices(self.caretIndex)
            lineN = self._lineNs[self.caretIndex]
            x = chrVerts[1, 0]  # x-coord of left edge
        # the y locations are the top and bottom of this line
        y1 = self._lineBottoms[lineN] / self._pixelScaling
        y2 = self._lineTops[lineN] / self._pixelScaling

        # char x pos has been corrected for anchor location already but lines
        # haven't
        verts = (np.array([[x, y1], [x, y2]]) + (0, self._anchorOffsetY))
        return convertToPix(vertices=verts,
                            pos=self.pos,
                            win=self.win,
                            units=self.units)
示例#7
0
def contains(thisElementArrayStim, x, y=None, units=None):
    """Returns True if a point x,y is inside the stimulus' border.

	Can accept variety of input options:
		+ two separate args, x and y
		+ one arg (list, tuple or array) containing two vals (x,y)
		+ an object with a getPos() method that returns x,y, such
			as a :class:`~psychopy.event.Mouse`.

	Returns `True` if the point is within the area defined either by its
	`border` attribute (if one defined), or its `vertices` attribute if
	there is no .border. This method handles
	complex shapes, including concavities and self-crossings.

	Note that, if your stimulus uses a mask (such as a Gaussian) then
	this is not accounted for by the `contains` method; the extent of the
	stimulus is determined purely by the size, position (pos), and
	orientation (ori) settings (and by the vertices for shape stimuli).

	See Coder demos: shapeContains.py
	"""
    # get the object in pixels
    if hasattr(x, 'border'):
        xy = x._borderPix  # access only once - this is a property
        units = 'pix'  # we can forget about the units
    elif hasattr(x, 'verticesPix'):
        # access only once - this is a property (slower to access)
        xy = x.verticesPix
        units = 'pix'  # we can forget about the units
    elif hasattr(x, 'getPos'):
        xy = x.getPos()
        units = x.units
    elif type(x) in [list, tuple, np.ndarray]:
        xy = np.array(x)
    else:
        xy = np.array((x, y))
    # try to work out what units x,y has
    if units is None:
        if hasattr(xy, 'units'):
            units = xy.units
        else:
            units = thisElementArrayStim.units
    if units != 'pix':
        xy = convertToPix(xy,
                          pos=(0, 0),
                          units=units,
                          win=thisElementArrayStim.win)
    # ourself in pixels
    if hasattr(thisElementArrayStim, 'border'):
        poly = thisElementArrayStim._borderPix  # e.g., outline vertices
    else:
        poly = thisElementArrayStim.verticesPix[:, :, 0:
                                                2]  # e.g., tesselated vertices

    return any(
        np.fromiter((visual.helpers.pointInPolygon(xy[0], xy[1], thisPoly)
                     for thisPoly in poly), np.bool))
示例#8
0
文件: text.py 项目: unshur/psychopy
 def posPix(self):
     """This determines the coordinates in pixels of the position for the
     current stimulus, accounting for pos and units. This property should
     automatically update if `pos` is changed"""
     #because this is a property getter we can check /on-access/ if it needs updating :-)
     if self._needVertexUpdate:
         self.__dict__['posPix'] = convertToPix(vertices = [0,0], pos = self.pos, units=self.units, win = self.win)
     self._needVertexUpdate = False
     return self.__dict__['posPix']
示例#9
0
 def posPix(self):
     """This determines the coordinates in pixels of the position for the
     current stimulus, accounting for pos and units. This property should
     automatically update if `pos` is changed"""
     #because this is a property getter we can check /on-access/ if it needs updating :-)
     if self._needVertexUpdate:
         self.__dict__['posPix'] = convertToPix(vertices = [0,0], pos = self.pos, units=self.units, win = self.win)
     self._needVertexUpdate = False
     return self.__dict__['posPix']
示例#10
0
    def _updateVertices(self):
        """Sets Stim.verticesPix and ._borderPix from pos, size, ori,
        flipVert, flipHoriz
        """
        # check whether stimulus needs flipping in either direction
        flip = np.array([1, 1])
        if hasattr(self, 'flipHoriz') and self.flipHoriz:
            flip[0] = -1  # True=(-1), False->(+1)
        if hasattr(self, 'flipVert') and self.flipVert:
            flip[1] = -1  # True=(-1), False->(+1)

        font = self.glFont
        # to start with the anchor is bottom left of *first line*
        if self._anchorY == 'top':
            self._anchorOffsetY = (-font.ascender / self._pixelScaling -
                                   self.padding)
        elif self._anchorY == 'center':
            self._anchorOffsetY = (
                self.size[1] / 2 -
                (font.height / 2 - font.descender) / self._pixelScaling -
                self.padding)
        elif self._anchorY == 'bottom':
            self._anchorOffsetY = (self.size[1] / 2 -
                                   font.descender / self._pixelScaling)
        else:
            raise ValueError('Unexpected error for _anchorY')

        if self._anchorX == 'right':
            self._anchorOffsetX = -(self.size[0] - self.padding) / 1.0
        elif self._anchorX == 'center':
            self._anchorOffsetX = -(self.size[0] - self.padding) / 2.0
        elif self._anchorX == 'left':
            self._anchorOffsetX = 0
        else:
            raise ValueError('Unexpected error for _anchorX')
        self.vertices = self._rawVerts + (self._anchorOffsetX,
                                          self._anchorOffsetY)

        vertsPix = convertToPix(vertices=self.vertices,
                                pos=self.pos,
                                win=self.win,
                                units=self.units)
        self.__dict__['verticesPix'] = vertsPix

        # tight bounding box
        L = self.vertices[:, 0].min()
        R = self.vertices[:, 0].max()
        B = self.vertices[:, 1].min()
        T = self.vertices[:, 1].max()
        tightW = R - L
        Xmid = (R + L) / 2
        tightH = T - B
        Ymid = (T + B) / 2
        self.box.size = tightW, tightH
        self.box.pos = Xmid, Ymid
        self._needVertexUpdate = False
示例#11
0
 def setHeight(self,height, log=True):
     """Set the height of the letters (including the entire box that surrounds the letters
     in the font). The width of the letters is then defined by the font.
     """
     self.heightPix = convertToPix(pos = numpy.array([0,0]),
                                   vertices=numpy.array([0,height]),
                                   units=self.units, win=self.win)[1]
     #need to update the font to reflect the change
     self.setFont(self.fontname, log=False)
     logAttrib(self, log, 'height', height)
示例#12
0
 def setHeight(self,height, log=True):
     """Set the height of the letters (including the entire box that surrounds the letters
     in the font). The width of the letters is then defined by the font.
     """
     self.heightPix = convertToPix(pos = numpy.array([0,0]),
                                   vertices=numpy.array([0,height]),
                                   units=self.units, win=self.win)[1]
     #need to update the font to reflect the change
     self.setFont(self.fontname, log=False)
     logAttrib(self, log, 'height', height)
示例#13
0
 def setHeight(self, height, log=True):
     """Set the height of the letters (including the entire box that surrounds the letters
     in the font). The width of the letters is then defined by the font.
     """
     self.heightPix = convertToPix(
         pos=numpy.array([0, 0]), vertices=numpy.array([0, height]), units=self.units, win=self.win
     )[1]
     # need to update the font to reflect the change
     self.setFont(self.fontname, log=False)
     if log and self.autoLog:
         self.win.logOnFlip("Set %s height=%.2f" % (self.name, height), level=logging.EXP, obj=self)
示例#14
0
    def wrapWidth(self, wrapWidth):
        """Int/float or None (set default).
        The width the text should run before wrapping.

        :ref:`Operations <attrib-operations>` supported."""
        if wrapWidth is None:
            if self.units in defaultWrapWidth:
                wrapWidth = defaultWrapWidth[self.units]
            else:
                raise AttributeError, "TextStim does now know a default wrap width for units %s" %(repr(self.units))
        self.__dict__['wrapWidth'] = wrapWidth
        self._wrapWidthPix = convertToPix(pos = numpy.array([0, 0]), vertices=numpy.array([self.wrapWidth, 0]), units=self.units, win=self.win)[0]
        self._needSetText = True
示例#15
0
文件: text.py 项目: unshur/psychopy
    def wrapWidth(self, wrapWidth):
        """Int/float or None (set default).
        The width the text should run before wrapping.

        :ref:`Operations <attrib-operations>` supported."""
        if wrapWidth is None:
            if self.units in defaultWrapWidth:
                wrapWidth = defaultWrapWidth[self.units]
            else:
                raise AttributeError, "TextStim does now know a default wrap width for units %s" %(repr(self.units))
        self.__dict__['wrapWidth'] = wrapWidth
        self._wrapWidthPix = convertToPix(pos = numpy.array([0, 0]), vertices=numpy.array([self.wrapWidth, 0]), units=self.units, win=self.win)[0]
        self._needSetText = True
示例#16
0
文件: text.py 项目: rpbaxter/psychopy
 def setHeight(self, height, log=True):
     """Set the height of the letters (including the entire box that surrounds the letters
     in the font). The width of the letters is then defined by the font.
     """
     self.heightPix = convertToPix(pos=numpy.array([0, 0]),
                                   vertices=numpy.array([0, height]),
                                   units=self.units,
                                   win=self.win)[1]
     #need to update the font to reflect the change
     self.setFont(self.fontname, log=False)
     if log and self.autoLog:
         self.win.logOnFlip("Set %s height=%.2f" % (self.name, height),
                            level=logging.EXP,
                            obj=self)
示例#17
0
    def _updateVertices(self):
        """Sets Stim.verticesPix from fieldPos.
        """

        # Handle the orientation, size and location of
        # each element in native units

        radians = 0.017453292519943295

        # so we can do matrix rotation of coords we need shape=[n*4,3]
        # but we'll convert to [n,4,3] after matrix math
        verts = numpy.zeros([self.nElements * 4, 3], 'd')
        wx = -self.sizes[:, 0] * numpy.cos(self.oris[:] * radians) / 2
        wy = self.sizes[:, 0] * numpy.sin(self.oris[:] * radians) / 2
        hx = self.sizes[:, 1] * numpy.sin(self.oris[:] * radians) / 2
        hy = self.sizes[:, 1] * numpy.cos(self.oris[:] * radians) / 2

        # X vals of each vertex relative to the element's centroid
        verts[0::4, 0] = -wx - hx
        verts[1::4, 0] = +wx - hx
        verts[2::4, 0] = +wx + hx
        verts[3::4, 0] = -wx + hx

        # Y vals of each vertex relative to the element's centroid
        verts[0::4, 1] = -wy - hy
        verts[1::4, 1] = +wy - hy
        verts[2::4, 1] = +wy + hy
        verts[3::4, 1] = -wy + hy

        # set of positions across elements
        positions = self.xys + self.fieldPos

        # depth
        verts[:, 2] = self.depths + self.fieldDepth
        # rotate, translate, scale by units
        if positions.shape[0] * 4 == verts.shape[0]:
            positions = positions.repeat(4, 0)
        verts[:, :2] = convertToPix(vertices=verts[:, :2],
                                    pos=positions,
                                    units=self.units,
                                    win=self.win)
        verts = verts.reshape([self.nElements, 4, 3])

        # assign to self attribute; make sure it's contiguous
        self.__dict__['verticesPix'] = numpy.require(verts, requirements=['C'])
        self._needVertexUpdate = False
示例#18
0
    def height(self, height):
        """Float/int or None (set default).
        The height of the letters (including the entire box that surrounds the letters
        in the font). The width of the letters is then defined by the font.

        :ref:`Operations <attrib-operations>` supported."""
        #height in pix (needs to be done after units which is done during _Base.__init__)
        if height is None:
            if self.units in defaultLetterHeight:
                height = defaultLetterHeight[self.units]
            else:
                raise AttributeError, "TextStim does now know a default letter height for units %s" %(repr(self.units))
        self.__dict__['height'] = height
        self._heightPix = convertToPix(pos = numpy.array([0, 0]), vertices=numpy.array([0, self.height]), units=self.units, win=self.win)[1]

        #need to update the font to reflect the change
        self.setFont(self.font, log=False)
示例#19
0
    def _updateVertices(self):
        """Sets Stim.verticesPix from fieldPos.
        """

        # Handle the orientation, size and location of
        # each element in native units

        radians = 0.017453292519943295

        # so we can do matrix rotation of coords we need shape=[n*4,3]
        # but we'll convert to [n,4,3] after matrix math
        verts = numpy.zeros([self.nElements * 4, 3], 'd')
        wx = -self.sizes[:, 0] * numpy.cos(self.oris[:] * radians) / 2
        wy = self.sizes[:, 0] * numpy.sin(self.oris[:] * radians) / 2
        hx = self.sizes[:, 1] * numpy.sin(self.oris[:] * radians) / 2
        hy = self.sizes[:, 1] * numpy.cos(self.oris[:] * radians) / 2

        # X vals of each vertex relative to the element's centroid
        verts[0::4, 0] = -wx - hx
        verts[1::4, 0] = +wx - hx
        verts[2::4, 0] = +wx + hx
        verts[3::4, 0] = -wx + hx

        # Y vals of each vertex relative to the element's centroid
        verts[0::4, 1] = -wy - hy
        verts[1::4, 1] = +wy - hy
        verts[2::4, 1] = +wy + hy
        verts[3::4, 1] = -wy + hy

        # set of positions across elements
        positions = self.xys + self.fieldPos

        # depth
        verts[:, 2] = self.depths + self.fieldDepth
        # rotate, translate, scale by units
        if positions.shape[0] * 4 == verts.shape[0]:
            positions = positions.repeat(4, 0)
        verts[:, :2] = convertToPix(vertices=verts[:, :2], pos=positions,
                                    units=self.units, win=self.win)
        verts = verts.reshape([self.nElements, 4, 3])

        # assign to self attribute; make sure it's contiguous
        self.__dict__['verticesPix'] = numpy.require(verts,
                                                     requirements=['C'])
        self._needVertexUpdate = False
示例#20
0
    def _create_trial_res(self, trace_let, trial_time, ptt, start_t_stamp,
                          trace_let_pix, scale, cursor_t, traces_pix):
        """ Creates the results dict that contains basic/essential trial info
        to be saved. """

        self.log.debug('Creating trial results')

        # original data + metadata
        self.trial_results = {'trace_let': trace_let, 'trial_time': trial_time,
                              'ix_block': self.block_idx,
                              'ix_trial': self.trial_idx, 'ptt': ptt,
                              'start_t_stamp': start_t_stamp}

        # new/extra metadata
        if scale:
            self.trial_results['scaling_matrix'] = self.stimuli['scaling_matrix']
        self.trial_results['traces_pix'] = traces_pix
        self.trial_results['n_traces'] = len(self.frame['traces'])
        self.trial_results['trial_duration'] = self.trial_settings['trial_duration']
        self.trial_results['flip'] = self.stimuli['flip']
        self.trial_results['the_box'] = self.frame['elements'][
            'the_box'].vertices.copy()

        self.trial_results['theBoxPix'] = self.frame['elements'][
            'the_box'].verticesPix

        self.trial_results['cursor_t'] = cursor_t

        if (trace_let != trace_let_pix).any():
            self.trial_results['pos_t_pix'] = trace_let_pix

        # in matlab i think this is theRect
        self.trial_results['winSize'] = self.win.size

        self.trial_results['template'] = self.stimuli['current_stim']
        stim_size = self.frame['elements']['template'].size
        stim_pos = self.frame['elements']['template'].pos
        self.trial_results['template_pix'] = convertToPix(self.stimuli['current_stim'],
                                                          units='norm',
                                                          pos=stim_pos,
                                                          win=self.win)
        self.trial_results['template_size'] = stim_size
        self.trial_results['template_pos'] = stim_pos
示例#21
0
    def contains(self, x, y=None, units=None):
        """Determines if a point x,y is inside the extent of the stimulus.

        Can accept variety of input options:
            + two separate args, x and y
            + one arg (list, tuple or array) containing two vals (x,y)
            + an object with a getPos() method that returns x,y, such
                as a :class:`~psychopy.event.Mouse`. Returns `True` if the point is
                within the area defined by `vertices`.

        This method handles complex shapes, including concavities and self-crossings.

        Note that, if your stimulus uses a mask (such as a Gaussian blob) then
        this is not accounted for by the `contains` method; the extent of the
        stmulus is determined purely by the size, pos and orientation settings
        (and by the vertices for shape stimuli).

        See coder demo, shapeContains.py
        """
        #get the object in pixels
        if hasattr(x, 'verticesPix'):
            xy = x.verticesPix #access only once - this is a property (slower to access)
            units = 'pix' #we can forget about the units
        elif hasattr(x, 'getPos'):
            xy = x.getPos()
            units = x.units
        elif type(x) in [list, tuple, numpy.ndarray]:
            xy = numpy.array(x)
        else:
            xy = numpy.array((x,y))
        #try to work out what units x,y has
        if units is None:
            if hasattr(xy, 'units'):
                units = xy.units
            else:
                units = self.units
        if units != 'pix':
            xy = convertToPix(xy, pos=0, units=units, win=self.win)
        # ourself in pixels
        selfVerts = self.verticesPix
        return pointInPolygon(xy[0], xy[1], poly = selfVerts)
示例#22
0
    def contains(self, x, y=None, units=None):
        """Determines if a point x,y is inside the extent of the stimulus.

        Can accept variety of input options:
            + two separate args, x and y
            + one arg (list, tuple or array) containing two vals (x,y)
            + an object with a getPos() method that returns x,y, such
                as a :class:`~psychopy.event.Mouse`. Returns `True` if the point is
                within the area defined by `vertices`.

        This method handles complex shapes, including concavities and self-crossings.

        Note that, if your stimulus uses a mask (such as a Gaussian blob) then
        this is not accounted for by the `contains` method; the extent of the
        stmulus is determined purely by the size, pos and orientation settings
        (and by the vertices for shape stimuli).

        See coder demo, shapeContains.py
        """
        #get the object in pixels
        if hasattr(x, 'verticesPix'):
            xy = x.verticesPix  #access only once - this is a property (slower to access)
            units = 'pix'  #we can forget about the units
        elif hasattr(x, 'getPos'):
            xy = x.getPos()
            units = x.units
        elif type(x) in [list, tuple, numpy.ndarray]:
            xy = numpy.array(x)
        else:
            xy = numpy.array((x, y))
        #try to work out what units x,y has
        if units is None:
            if hasattr(xy, 'units'):
                units = xy.units
            else:
                units = self.units
        if units != 'pix':
            xy = convertToPix(xy, pos=0, units=units, win=self.win)
        # ourself in pixels
        selfVerts = self.verticesPix
        return pointInPolygon(xy[0], xy[1], poly=selfVerts)
示例#23
0
 def _updateVertices(self):
     """Sets Stim.verticesPix from pos and size
     """
     if hasattr(self, 'vertices'):
         verts = self.vertices
     else:
         verts = self._verticesBase
     #check wheher stimulus needs flipping in either direction
     flip = numpy.array([1,1])
     if hasattr(self, 'flipHoriz'):
         flip[0] = self.flipHoriz*(-2)+1#True=(-1), False->(+1)
     if hasattr(self, 'flipVert'):
         flip[1] = self.flipVert*(-2)+1#True=(-1), False->(+1)
     # set size and orientation
     verts = numpy.dot(self.size*verts*flip, self._rotationMatrix)
     #then combine with position and convert to pix
     verts = convertToPix(vertices=verts, pos=self.pos, win=self.win, units=self.units)
     #assign to self attrbute
     self.__dict__['verticesPix'] = verts
     self._needVertexUpdate = False
     self._needUpdate = True #but we presumably need to update the list
示例#24
0
def convertParamToPix(value, win, units):
    """
    Convert value to numpy array
    Parameters
    ----------
    value : str, int, float, list, tuple
        Parameter value to be converted to pixels
    win : TestWin object
        A false window with necessary attributes for converting component
        parameters to pixels
    units : str
        Screen units

    Returns
    -------
    numpy array
        Parameter converted to pixels in numpy array
    """
    if isinstance(value, str):
        value = array(ast.literal_eval(value))
    else:
        value = array(value)
    return monitorunittools.convertToPix(value, array([0, 0]), units=units, win=win) * 2
示例#25
0
 def _updateVertices(self):
     """Sets Stim.verticesPix from pos and size
     """
     if hasattr(self, 'vertices'):
         verts = self.vertices
     else:
         verts = self._verticesBase
     #check wheher stimulus needs flipping in either direction
     flip = numpy.array([1, 1])
     if hasattr(self, 'flipHoriz'):
         flip[0] = self.flipHoriz * (-2) + 1  #True=(-1), False->(+1)
     if hasattr(self, 'flipVert'):
         flip[1] = self.flipVert * (-2) + 1  #True=(-1), False->(+1)
     # set size and orientation
     verts = numpy.dot(self.size * verts * flip, self._rotationMatrix)
     #then combine with position and convert to pix
     verts = convertToPix(vertices=verts,
                          pos=self.pos,
                          win=self.win,
                          units=self.units)
     #assign to self attrbute
     self.__dict__['verticesPix'] = verts
     self._needVertexUpdate = False
     self._needUpdate = True  #but we presumably need to update the list
示例#26
0
    def _updateVertices(self):
        """Sets Stim.verticesPix and ._borderPix from pos, size, ori,
        flipVert, flipHoriz
        """
        # check whether stimulus needs flipping in either direction
        flip = np.array([1, 1])
        if hasattr(self, 'flipHoriz') and self.flipHoriz:
            flip[0] = -1  # True=(-1), False->(+1)
        if hasattr(self, 'flipVert') and self.flipVert:
            flip[1] = -1  # True=(-1), False->(+1)

        if hasattr(self, 'vertices'):
            verts = self.vertices
        else:
            verts = self._verticesBase

        verts = convertToPix(vertices=verts,
                             pos=self.pos,
                             win=self.win,
                             units=self.units)
        self.__dict__['verticesPix'] = verts

        self.box.size = self.size
        self._needVertexUpdate = False
示例#27
0
    def __init__(self, win,
                 text="Hello World",
                 font="",
                 pos=(0.0,0.0),
                 depth=0,
                 rgb=None,
                 color=(1.0,1.0,1.0),
                 colorSpace='rgb',
                 opacity=1.0,
                 contrast=1.0,
                 units="",
                 ori=0.0,
                 height=None,
                 antialias=True,
                 bold=False,
                 italic=False,
                 alignHoriz='center',
                 alignVert='center',
                 fontFiles=[],
                 wrapWidth=None,
                 flipHoriz=False, flipVert=False,
                 name='', autoLog=True):
        """
        :Parameters:
            win: A :class:`Window` object.
                Required - the stimulus must know where to draw itself
            text:
                The text to be rendered
            height:
                Height of the characters (including the ascent of the letter and the descent)
            antialias:
                boolean to allow (or not) antialiasing the text
            bold:
                Make the text bold (better to use a bold font name)
            italic:
                Make the text italic (better to use an actual italic font)
            alignHoriz:
                The horizontal alignment ('left', 'right' or 'center')
            alignVert:
                The vertical alignment ('top', 'bottom' or 'center')
            fontFiles:
                A list of additional files if the font is not in the standard system location (include the full path)
            wrapWidth:
                The width the text should run before wrapping
            flipHoriz : boolean
                Mirror-reverse the text in the left-right direction
            flipVert : boolean
                Mirror-reverse the text in the up-down direction
        """

        #what local vars are defined (these are the init params) for use by __repr__
        self._initParams = dir()
        self._initParams.remove('self')

        super(TextStim, self).__init__(win, units=units, name=name, autoLog=False)

        self.useShaders = win._haveShaders  #use shaders if available by default, this is a good thing
        self._needUpdate = True
        self.alignHoriz = alignHoriz
        self.alignVert = alignVert
        self.antialias = antialias
        self.bold=bold
        self.italic=italic
        self.text='' #NB just a placeholder - real value set below
        self.depth=depth
        self.ori=ori
        self.flipHoriz = flipHoriz
        self.flipVert = flipVert
        self._pygletTextObj=None

        self.pos= numpy.array(pos, float)

        #height in pix (needs to be done after units which is done during _Base.__init__)
        if height==None:
            if self.units in defaultLetterHeight:
                height = defaultLetterHeight[self.units]
            else:
                raise AttributeError, "TextStim does now know a default letter height for units %s" %(repr(self.units))
        if wrapWidth==None:
            if self.units in defaultWrapWidth:
                wrapWidth = defaultWrapWidth[self.units]
            else:
                raise AttributeError, "TextStim does now know a default wrap width for units %s" %(repr(self.units))

        #treat letter height and wrapWidth as vertices (in degFlatPos they should not be 'corrected')
        wh = convertToPix(pos = numpy.array([0,0]), vertices=numpy.array([wrapWidth,height]), units=self.units, win=self.win)
        self._wrapWidthPix, self.heightPix = wh
        #generate the texture and list holders
        self._listID = GL.glGenLists(1)
        if not self.win.winType=="pyglet":#pygame text needs a surface to render to
            self._texID = GL.GLuint()
            GL.glGenTextures(1, ctypes.byref(self._texID))

        self.colorSpace=colorSpace
        if rgb!=None:
            logging.warning("Use of rgb arguments to stimuli are deprecated. Please use color and colorSpace args instead")
            self.setColor(rgb, colorSpace='rgb', log=False)
        else:
            self.setColor(color, log=False)

        for thisFont in fontFiles:
            pyglet.font.add_file(thisFont)
        self.setFont(font, log=False)
        self.opacity = float(opacity)
        self.contrast = float(contrast)
        self.setText(text, log=False) #self.width and self.height get set with text and calcSizeRendered is called
        self._needUpdate = True

        #set autoLog (now that params have been initialised)
        self.autoLog= autoLog
        if autoLog:
            logging.exp("Created %s = %s" %(self.name, str(self)))
示例#28
0
 def _calcPosRendered(self):
     """Calculate the pos of the stimulus in pixels"""
     self._posRendered = convertToPix(pos=self.pos,
                                      vertices=numpy.array([0, 0]),
                                      units=self.units,
                                      win=self.win)
示例#29
0
 def _calcPosRendered(self):
     """Calculate the pos of the stimulus in pixels"""
     self._posRendered = convertToPix(pos=self.pos,
                                      vertices=numpy.array([0, 0]),
                                      units=self.units, win=self.win)
示例#30
0
    def __init__(self, win,
                 text="Hello World",
                 font="",
                 pos=(0.0,0.0),
                 depth=0,
                 rgb=None,
                 color=(1.0,1.0,1.0),
                 colorSpace='rgb',
                 opacity=1.0,
                 contrast=1.0,
                 units="",
                 ori=0.0,
                 height=None,
                 antialias=True,
                 bold=False,
                 italic=False,
                 alignHoriz='center',
                 alignVert='center',
                 fontFiles=[],
                 wrapWidth=None,
                 flipHoriz=False, flipVert=False,
                 name='', autoLog=True):
        """
        :Parameters:
            win: A :class:`Window` object.
                Required - the stimulus must know where to draw itself
            text:
                The text to be rendered
            height:
                Height of the characters (including the ascent of the letter and the descent)
            antialias:
                boolean to allow (or not) antialiasing the text
            bold:
                Make the text bold (better to use a bold font name)
            italic:
                Make the text italic (better to use an actual italic font)
            alignHoriz:
                The horizontal alignment ('left', 'right' or 'center')
            alignVert:
                The vertical alignment ('top', 'bottom' or 'center')
            fontFiles:
                A list of additional files if the font is not in the standard system location (include the full path)
            wrapWidth:
                The width the text should run before wrapping
            flipHoriz : boolean
                Mirror-reverse the text in the left-right direction
            flipVert : boolean
                Mirror-reverse the text in the up-down direction
        """

        #what local vars are defined (these are the init params) for use by __repr__
        self._initParams = dir()
        self._initParams.remove('self')

        super(TextStim, self).__init__(win, units=units, name=name, autoLog=False)

        self.useShaders = win._haveShaders  #use shaders if available by default, this is a good thing
        self._needUpdate = True
        self.alignHoriz = alignHoriz
        self.alignVert = alignVert
        self.antialias = antialias
        self.bold=bold
        self.italic=italic
        self.text='' #NB just a placeholder - real value set below
        self.depth=depth
        self.ori=ori
        self.flipHoriz = flipHoriz
        self.flipVert = flipVert
        self._pygletTextObj=None

        self.pos= numpy.array(pos, float)

        #height in pix (needs to be done after units which is done during _Base.__init__)
        if height==None:
            if self.units in defaultLetterHeight:
                height = defaultLetterHeight[self.units]
            else:
                raise AttributeError, "TextStim does now know a default letter height for units %s" %(repr(self.units))
        if wrapWidth==None:
            if self.units in defaultWrapWidth:
                wrapWidth = defaultWrapWidth[self.units]
            else:
                raise AttributeError, "TextStim does now know a default wrap width for units %s" %(repr(self.units))

        #treat letter height and wrapWidth as vertices (in degFlatPos they should not be 'corrected')
        wh = convertToPix(pos = numpy.array([0,0]), vertices=numpy.array([wrapWidth,height]), units=self.units, win=self.win)
        self._wrapWidthPix, self.heightPix = wh
        #generate the texture and list holders
        self._listID = GL.glGenLists(1)
        if not self.win.winType=="pyglet":#pygame text needs a surface to render to
            self._texID = GL.GLuint()
            GL.glGenTextures(1, ctypes.byref(self._texID))

        self.colorSpace=colorSpace
        if rgb!=None:
            logging.warning("Use of rgb arguments to stimuli are deprecated. Please use color and colorSpace args instead")
            self.setColor(rgb, colorSpace='rgb', log=False)
        else:
            self.setColor(color, log=False)

        for thisFont in fontFiles:
            pyglet.font.add_file(thisFont)
        self.setFont(font, log=False)
        self.opacity = float(opacity)
        self.contrast = float(contrast)
        self.setText(text, log=False) #self.width and self.height get set with text and calcSizeRendered is called
        self._needUpdate = True

        #set autoLog (now that params have been initialised)
        self.autoLog= autoLog
        if autoLog:
            logging.exp("Created %s = %s" %(self.name, str(self)))
示例#31
0
    def create_frame(self, stimuli_idx, scale=True):

        self.frame['elements'] = {}

        self.frame['elements']['template'] = create_element(
            'template',
            win=self.win,
            image=utils.template_to_image(
                self.get_stimuli(stimuli_idx, scale=scale),
                f'{self.stimuli["fname"][:-4]}_{stimuli_idx}',
                self.paths['data']/'template_images',
                lineWidth=15
            ),
            size=self.block_settings['size'] * 1.6725  # scaling
        )
        # uncomment below to draw old template to check how the image
        # matches up with it

        # # seems to top out after like 10 or 20:
        # https://github.com/psychopy/psychopy/issues/818
        # from psychopy.visual import ShapeStim
        # self.frame['elements']['old_template'] = visual.ShapeStim(win=self.win,
        #                                             vertices=self.get_stimuli(stimuli_idx,scale=scale),
        #                                             lineWidth=100,
        #                                             closeShape=False,
        #                                             interpolate=True,
        #                                             ori=0,
        #                                             pos=(0,0),
        #                                             size=1.5,
        #                                             units='norm',
        #                                             fillColor='blue',
        #                                             lineColor='blue',
        #                                             #windingRule=True,
        #                                             )
        # self.frame['elements']['template'].setOpacity(0.5)

        self.frame['elements']['the_box'] = create_element('the_box',
                                                           win=self.win,
                                                           vertices=self.stimuli['the_box']
                                                           )

        self.frame['elements']['trial_number'] = create_element(
            'trial_number',
            win=self.win,
            text=f'Trial {self.trial_idx}/{self.block_settings["n_trials"]}',
        )

        self.frame['elements']['cursor'] = create_element(
            'cursor',
            win=self.win,
            pos=convertToPix(
                # so the 1.5 comes from how much the original template had to be scaled by after being converted
                # to norm units. the 1.6.. in the template section is how much the resulting image of the template had
                # to be scaled by in order to match up with the original template when drawn on top of each other
                self.trial_settings['cursor_start_pos'] * 1.5 * self.block_settings['size'],
                (0, 0),
                'norm',
                self.win
            )
        )

        max_trace_len = 10000  # Should be more points than would ever be drawn
        self.frame['trace_vertices'] = np.zeros([max_trace_len, 2])
        self.frame['trace_vertices'][0] = \
            convertToPix(self.trial_settings['cursor_start_pos'] * 1.5 * self.block_settings['size'],
                         (0, 0),
                         'norm',
                         self.win)
        # TODO: clicking NOT on cursor (post startpoint press) results in no trace being drawn - fix
        # trace starts to get drawn after sometime - some kind of lag on recording of trace vertices..
        self.frame['elements']['trace1'] = create_element(
           'trace',                           # we will dynamically create more -> draw interupted lines
            win=self.win,
            vertices=self.frame['trace_vertices'][0:1],          # initialize empty - now take first point?
        )
        self.frame['traces'].append('trace1')

        self.frame['elements']['instructions'] = create_element(
            'instructions',
            win=self.win,
            image=self.paths['instructions']
        )

        # start_point
        start_point_size = 0.05
        self.frame['elements']['start_point'] = create_element(
            'start_point',
            win=self.win,
            size=(start_point_size, start_point_size * self.win_settings['aspect_ratio'])
        )

        self.frame['elements']['time_bar'] = create_element(
            'time_bar',
            win=self.win
        )
示例#32
0
    def __init__(self, win, text, font,
                 pos=(0, 0), units=None, letterHeight=None,
                 size=None,
                 color=(1.0, 1.0, 1.0),
                 colorSpace='rgb',
                 contrast=1,
                 opacity=1.0,
                 bold=False,
                 italic=False,
                 lineSpacing=1.0,
                 padding=None,  # gap between box and text
                 anchor='center',
                 alignment='left',
                 fillColor=None,
                 borderWidth=2,
                 borderColor=None,
                 flipHoriz=False,
                 flipVert=False,
                 editable=False,
                 name='',
                 autoLog=None,
                 onTextCallback=None):
        """

        Parameters
        ----------
        win
        text
        font
        pos
        units
        letterHeight
        size : Specifying None gets the default size for this type of unit.
            Specifying [None, None] gets a TextBox that's expandable in both
            dimensions. Specifying [0.75, None] gets a textbox that expands in the
            length but fixed at 0.75 units in the width
        color
        colorSpace
        contrast
        opacity
        bold
        italic
        lineSpacing
        padding
        anchor
        alignment
        fillColor
        borderWidth
        borderColor
        flipHoriz
        flipVert
        editable
        name
        autoLog
        """

        BaseVisualStim.__init__(self, win, units=units, name=name)
        self.win = win
        self.colorSpace = colorSpace
        self.color = color
        self.contrast = contrast
        self.opacity = opacity
        self.onTextCallback = onTextCallback

        # first set params needed to create font (letter sizes etc)
        if letterHeight is None:
            self.letterHeight = defaultLetterHeight[self.units]
        else:
            self.letterHeight = letterHeight

        # self._pixLetterHeight helps get font size right but not final layout
        if 'deg' in self.units:  # treat deg, degFlat or degFlatPos the same
            scaleUnits = 'deg'  # scale units are just for font resolution
        else:
            scaleUnits = self.units
        self._pixLetterHeight = convertToPix(
                self.letterHeight, pos=0, units=scaleUnits, win=self.win)
        self._pixelScaling = self._pixLetterHeight / self.letterHeight
        if size is None:
            size = [defaultBoxWidth[self.units], None]
        self.size = size  # but this will be updated later to actual size
        self.bold = bold
        self.italic = italic
        self.lineSpacing = lineSpacing
        if padding is None:
            padding = letterHeight / 2.0
        self.padding = padding
        self.glFont = None  # will be set by the self.font attribute setter
        self.font = font

        # once font is set up we can set the shader (depends on rgb/a of font)
        if self.glFont.atlas.format == 'rgb':
            global rgbShader
            self.shader = rgbShader = shaders.Shader(
                    shaders.vertSimple, shaders.fragTextBox2)
        else:
            global alphaShader
            self.shader = alphaShader = shaders.Shader(
                    shaders.vertSimple, shaders.fragTextBox2alpha)
        self._needVertexUpdate = False  # this will be set True during layout

        # standard stimulus params
        self.pos = pos
        self.ori = 0.0
        self.depth = 0.0
        # used at render time
        self._lines = None  # np.array the line numbers for each char
        self._colors = None
        self.flipHoriz = flipHoriz
        self.flipVert = flipVert
        # params about positioning (after layout has occurred)
        self.anchor = anchor  # 'center', 'top_left', 'bottom-center'...
        self.alignment = alignment

        # box border and fill
        w, h = self.size
        self.borderWidth = borderWidth
        self.borderColor = borderColor
        self.fillColor = fillColor

        self.box = Rect(
                win, pos=self.pos,
                units=self.units,
                lineWidth=borderWidth, lineColor=borderColor,
                fillColor=fillColor, opacity=self.opacity,
                autoLog=False, fillColorSpace=self.colorSpace)
        # also bounding box (not normally drawn but gives tight box around chrs)
        self.boundingBox = Rect(
                win, pos=self.pos,
                units=self.units,
                lineWidth=1, lineColor=None, fillColor=fillColor, opacity=0.1,
                autoLog=False)
        self.pallette = { # If no focus
                'lineColor': borderColor,
                'lineRGB': self.box.lineRGB,
                'lineWidth': borderWidth,
                'fillColor': fillColor,
                'fillRGB': self.box.fillRGB
        }
        # then layout the text (setting text triggers _layout())
        self.text = text

        # caret
        self.editable = editable
        self.caret = Caret(self, color=self.color, width=5)
        self._hasFocus = False
        if editable:  # may yet gain focus if the first editable obj
            self.win.addEditable(self)

        self.autoLog = autoLog
示例#33
0
    def _updateVertices(self):
        """Sets Stim.verticesPix and ._borderPix from pos, size, ori,
        flipVert, flipHoriz
        """
        # check whether stimulus needs flipping in either direction
        flip = np.array([1, 1])
        if hasattr(self, 'flipHoriz') and self.flipHoriz:
            flip[0] = -1  # True=(-1), False->(+1)
        if hasattr(self, 'flipVert') and self.flipVert:
            flip[1] = -1  # True=(-1), False->(+1)

        font = self.glFont
        # to start with the anchor is bottom left of *first line*
        if self._anchorY == 'top':
            self._anchorOffsetY = (-font.ascender / self._pixelScaling
                                   - self.padding)
            boxOffsetY = - self.size[1] / 2.0
        elif self._anchorY == 'center':
            self._anchorOffsetY = (
                    self.size[1] / 2
                    - (font.height / 2 - font.descender) / self._pixelScaling
                    - self.padding
            )
            boxOffsetY = 0
        elif self._anchorY == 'bottom':
            self._anchorOffsetY = (
                    self.size[1]
                    - (font.height / 2 + font.ascender) / self._pixelScaling
            )
            # self._anchorOffsetY = (-font.ascender / self._pixelScaling
            #                        - self.padding)
            boxOffsetY = + (self.size[1]) / 2.0
        else:
            raise ValueError('Unexpected value for _anchorY')

        # calculate anchor offsets (text begins on left=0, box begins center=0)
        if self._anchorX == 'right':
            self._anchorOffsetX = - self.size[0] + self.padding
            boxOffsetX = - self.size[0] / 2.0
        elif self._anchorX == 'center':
            self._anchorOffsetX = - self.size[0] / 2.0 + self.padding
            boxOffsetX = 0
        elif self._anchorX == 'left':
            self._anchorOffsetX = 0 + self.padding
            boxOffsetX = + self.size[0] / 2.0
        else:
            raise ValueError('Unexpected value for _anchorX')
        self.vertices = self._rawVerts + (self._anchorOffsetX, self._anchorOffsetY)

        vertsPix = convertToPix(vertices=self.vertices,
                                pos=self.pos,
                                win=self.win, units=self.units)
        self.__dict__['verticesPix'] = vertsPix

        # tight bounding box
        if self.vertices.shape[0] < 1:  # editable box with no letters?
            self.boundingBox.size = 0, 0
            self.boundingBox.pos = self.pos
        else:
            L = self.vertices[:, 0].min()
            R = self.vertices[:, 0].max()
            B = self.vertices[:, 1].min()
            T = self.vertices[:, 1].max()
            tightW = R-L
            Xmid = (R+L)/2
            tightH = T-B
            Ymid = (T+B)/2
            # for the tight box anchor offset is included in vertex calcs
            self.boundingBox.size = tightW, tightH
            self.boundingBox.pos = self.pos + (Xmid, Ymid)
        # box (larger than bounding box) needs anchor offest adding
        self.box.pos = self.pos + (boxOffsetX, boxOffsetY)
        self.box.size = self.size  # this might have changed from _requested

        self._needVertexUpdate = False
示例#34
0
    def __init__(
            self,
            win,
            text,
            font,
            pos=(0, 0),
            units='pix',
            letterHeight=None,
            size=None,
            color=(1.0, 1.0, 1.0),
            colorSpace='rgb',
            opacity=1.0,
            bold=False,
            italic=False,
            lineSpacing=1.0,
            padding=None,  # gap between box and text
            anchor='center',
            fillColor=None,
            borderColor=None,
            flipHoriz=False,
            flipVert=False,
            editable=False,
            name='',
            autoLog=None):

        BaseVisualStim.__init__(self,
                                win,
                                units=units,
                                name=name,
                                autoLog=autoLog)
        self.win = win
        # first set params needed to create font (letter sizes etc)
        if letterHeight is None:
            self.letterHeight = defaultLetterHeight[units]
        else:
            self.letterHeight = letterHeight
        # self._pixLetterHeight helps get font size right but not final layout
        if 'deg' in units:  # treat deg, degFlat or degFlatPos the same
            scaleUnits = 'deg'  # scale units are just for font resolution
        else:
            scaleUnits = units
        self._pixLetterHeight = convertToPix(self.letterHeight,
                                             pos=0,
                                             units=scaleUnits,
                                             win=self.win)
        if size is None:
            size = (defaultBoxWidth[units], -1)
        self._requestedSize = size  # (-1 in either dim means not constrained)
        self.size = size  # but this will be updated later to actual size
        self.bold = bold
        self.italic = italic
        self.lineSpacing = lineSpacing
        if padding is None:
            padding = defaultLetterHeight[units] / 2.0
        self.padding = padding
        self.glFont = None  # will be set by the self.font attribute setter
        self.font = font
        # once font is set up we can set the shader (depends on rgb/a of font)
        if self.glFont.atlas.format == 'rgb':
            global rgbShader
            self.shader = rgbShader = shaders.Shader(shaders.vertSimple,
                                                     shaders.fragTextBox2)
        else:
            global alphaShader
            self.shader = alphaShader = shaders.Shader(
                shaders.vertSimple, shaders.fragTextBox2alpha)
        # params about positioning
        self.anchor = anchor  # 'center', 'top_left', 'bottom-center'...
        self._needVertexUpdate = False  # this will be set True during layout
        # standard stimulus params
        self.pos = pos
        self.color = color
        self.colorSpace = colorSpace
        self.opacity = opacity
        # used at render time
        self._lines = None  # np.array the line numbers for each char
        self._colors = None

        self.flipHoriz = flipHoriz
        self.flipVert = flipVert
        self.text = text  # setting this triggers a _layout() call so do last
        # box border and fill
        self.box = Rect(win,
                        pos=pos,
                        width=self.size[0],
                        height=self.size[1],
                        units=units,
                        lineColor=borderColor,
                        fillColor=fillColor)
        self.borderColor = borderColor
        self.fillColor = fillColor

        # caret
        self.editable = editable
        self.caretIndex = None
        if editable:
            self.win.addEditable(self)
示例#35
0
    def __init__(
            self,
            win,
            text,
            font,
            pos=(0, 0),
            units=None,
            letterHeight=None,
            size=None,
            color=(1.0, 1.0, 1.0),
            colorSpace='rgb',
            fillColor=None,
            fillColorSpace=None,
            borderWidth=2,
            borderColor=None,
            borderColorSpace=None,
            contrast=1,
            opacity=None,
            bold=False,
            italic=False,
            lineSpacing=1.0,
            padding=None,  # gap between box and text
            anchor='center',
            alignment='left',
            flipHoriz=False,
            flipVert=False,
            editable=False,
            lineBreaking='default',
            name='',
            autoLog=None,
            onTextCallback=None):
        """

        Parameters
        ----------
        win
        text
        font
        pos
        units
        letterHeight
        size : Specifying None gets the default size for this type of unit.
            Specifying [None, None] gets a TextBox that's expandable in both
            dimensions. Specifying [0.75, None] gets a textbox that expands in the
            length but fixed at 0.75 units in the width
        color
        colorSpace
        contrast
        opacity
        bold
        italic
        lineSpacing
        padding
        anchor
        alignment
        fillColor
        borderWidth
        borderColor
        flipHoriz
        flipVert
        editable
        lineBreaking: Specifying 'default', text will be broken at a set of 
            characters defined in the module. Specifying 'uax14', text will be 
            broken in accordance with UAX#14 (Unicode Line Breaking Algorithm).
        name
        autoLog
        """

        BaseVisualStim.__init__(self, win, units=units, name=name)
        self.win = win
        self.colorSpace = colorSpace
        ColorMixin.foreColor.fset(
            self, color
        )  # Have to call the superclass directly on init as text has not been set
        self.onTextCallback = onTextCallback

        # first set params needed to create font (letter sizes etc)
        if letterHeight is None:
            self.letterHeight = defaultLetterHeight[self.units]
        else:
            self.letterHeight = letterHeight
        # self._pixLetterHeight helps get font size right but not final layout
        if 'deg' in self.units:  # treat deg, degFlat or degFlatPos the same
            scaleUnits = 'deg'  # scale units are just for font resolution
        else:
            scaleUnits = self.units
        self._pixLetterHeight = convertToPix(self.letterHeight,
                                             pos=0,
                                             units=scaleUnits,
                                             win=self.win)
        if isinstance(self._pixLetterHeight, np.ndarray):
            # If pixLetterHeight is an array, take the Height value
            self._pixLetterHeight = self._pixLetterHeight[1]
        self._pixelScaling = self._pixLetterHeight / self.letterHeight
        if size is None:
            size = [defaultBoxWidth[self.units], None]
        self.size = size  # but this will be updated later to actual size
        self.bold = bold
        self.italic = italic
        self.lineSpacing = lineSpacing
        if padding is None:
            padding = self.letterHeight / 2.0
        self.padding = padding
        self.glFont = None  # will be set by the self.font attribute setter
        self.font = font
        # If font not found, default to Open Sans Regular and raise alert
        if not self.glFont:
            alerts.alert(
                4325, self, {
                    'font':
                    font,
                    'weight':
                    'bold' if self.bold is True else
                    'regular' if self.bold is False else self.bold,
                    'style':
                    'italic' if self.italic else '',
                    'name':
                    self.name
                })
            self.bold = False
            self.italic = False
            self.font = "Open Sans"

        # once font is set up we can set the shader (depends on rgb/a of font)
        if self.glFont.atlas.format == 'rgb':
            global rgbShader
            self.shader = rgbShader = shaders.Shader(shaders.vertSimple,
                                                     shaders.fragTextBox2)
        else:
            global alphaShader
            self.shader = alphaShader = shaders.Shader(
                shaders.vertSimple, shaders.fragTextBox2alpha)
        self._needVertexUpdate = False  # this will be set True during layout

        # standard stimulus params
        self.pos = pos
        self.ori = 0.0
        self.depth = 0.0
        # used at render time
        self._lines = None  # np.array the line numbers for each char
        self._colors = None
        self._styles = None
        self.flipHoriz = flipHoriz
        self.flipVert = flipVert
        # params about positioning (after layout has occurred)
        self.anchor = anchor  # 'center', 'top_left', 'bottom-center'...
        self.alignment = alignment

        # box border and fill
        w, h = self.size
        self.borderWidth = borderWidth
        self.borderColor = borderColor
        self.fillColor = fillColor
        self.contrast = contrast
        self.opacity = opacity

        self.box = Rect(win,
                        pos=self.pos,
                        units=self.units,
                        lineWidth=borderWidth,
                        lineColor=borderColor,
                        fillColor=fillColor,
                        opacity=self.opacity,
                        autoLog=False,
                        fillColorSpace=self.colorSpace)
        # also bounding box (not normally drawn but gives tight box around chrs)
        self.boundingBox = Rect(win,
                                pos=self.pos,
                                units=self.units,
                                lineWidth=1,
                                lineColor=None,
                                fillColor=fillColor,
                                opacity=0.1,
                                autoLog=False)
        # set linebraking option
        if lineBreaking not in ('default', 'uax14'):
            raise ValueError("Unknown lineBreaking option ({}) is"
                             "specified.".format(lineBreaking))
        self._lineBreaking = lineBreaking
        # then layout the text (setting text triggers _layout())
        self._text = ''
        self.text = self.startText = text if text is not None else ""

        # caret
        self.editable = editable
        self.caret = Caret(self, color=self.color, width=5)

        self.autoLog = autoLog