def writeInitCodeJS(self, buff): inits = getInitVals(self.params) for param in inits: if inits[param].val in ['', None, 'None', 'none']: inits[param].val = 'undefined' # Check for unsupported units if inits['units'].val == 'from exp settings': inits['units'] = copy.copy(self.exp.settings.params['Units']) if inits['units'].val in ['cm', 'deg', 'degFlatPos', 'degFlat']: msg = ("'{units}' units for your '{name}' Slider are not currently supported for PsychoJS: " "switching units to 'height'. Note, this will affect the size and positioning of '{name}'.") logging.warning(msg.format(units=inits['units'].val, name=inits['name'].val)) inits['units'].val = "height" boolConverter = {False: 'false', True: 'true'} sliderStyles = {'slider': 'SLIDER', 'scrollbar': 'SLIDER', '()': 'RATING', 'rating': 'RATING', 'radio': 'RADIO', 'labels45': 'LABELS_45', 'whiteOnBlack': 'WHITE_ON_BLACK', 'triangleMarker': 'TRIANGLE_MARKER'} # If no style given, set default 'rating' as list if len(inits['styles'].val) == 0: inits['styles'].val = 'rating' # reformat styles for JS # concatenate styles and tweaks tweaksList = utils.listFromString(self.params['styleTweaks'].val) if type(inits['styles'].val) == list: # from an experiment <2021.1 stylesList = inits['styles'].val + tweaksList else: stylesList = [inits['styles'].val] + tweaksList stylesListJS = [sliderStyles[this] for this in stylesList] # if not isinstance(inits['styleTweaks'].val, (tuple, list)): # inits['styleTweaks'].val = [inits['styleTweaks'].val] # inits['styleTweaks'].val = ', '.join(["visual.Slider.StyleTweaks.{}".format(adj) # for adj in inits['styleTweaks'].val]) # convert that to string and JS-ify inits['styles'].val = py2js.expression2js(str(stylesListJS)) inits['styles'].valType = 'code' inits['depth'] = -self.getPosInRoutine() # build up an initialization string for Slider(): initStr = ("{name} = new visual.Slider({{\n" " win: psychoJS.window, name: '{name}',\n" " size: {size}, pos: {pos}, units: {units},\n" " labels: {labels}, ticks: {ticks},\n" " granularity: {granularity}, style: {styles},\n" " color: new util.Color({color}), \n" " fontFamily: {font}, bold: true, italic: false, depth: {depth}, \n" ).format(**inits) initStr += (" flip: {flip},\n" "}});\n\n").format(flip=boolConverter[inits['flip'].val]) buff.writeIndentedLines(initStr)
def writeInitCodeJS(self, buff): inits = getInitVals(self.params) for param in inits: if inits[param].val in ['', None, 'None', 'none']: inits[param].val = 'undefined' # Check for unsupported units if inits['units'].val == 'from exp settings': inits['units'] = copy.copy(self.exp.settings.params['Units']) if inits['units'].val in ['cm', 'deg', 'degFlatPos', 'degFlat']: msg = ( "'{units}' units for your '{name}' Slider are not currently supported for PsychoJS: " "switching units to 'height'. Note, this will affect the size and positioning of '{name}'." ) logging.warning( msg.format(units=inits['units'].val, name=inits['name'].val)) inits['units'].val = "height" boolConverter = {False: 'false', True: 'true'} sliderStyles = { 'slider': 'SLIDER', '()': 'RATING', 'rating': 'RATING', 'radio': 'RADIO', 'labels45': 'LABELS_45', 'whiteOnBlack': 'WHITE_ON_BLACK', 'triangleMarker': 'TRIANGLE_MARKER' } # If no style given, set default 'rating' as list if len(inits['styles'].val) == 0: inits['styles'].val = ['rating'] # reformat styles for JS inits['styles'].val = ', '.join([ "visual.Slider.Style.{}".format(sliderStyles[style]) for style in inits['styles'].val ]) # add comma so is treated as tuple in py2js and converted to list, as required inits['styles'].val += ',' inits['styles'].val = py2js.expression2js(inits['styles'].val) inits['depth'] = -self.getPosInRoutine() # build up an initialization string for Slider(): initStr = ( "{name} = new visual.Slider({{\n" " win: psychoJS.window, name: '{name}',\n" " size: {size}, pos: {pos}, units: {units},\n" " labels: {labels}, ticks: {ticks},\n" " granularity: {granularity}, style: {styles},\n" " color: new util.Color({color}), \n" " fontFamily: {font}, bold: true, italic: false, depth: {depth}, \n" ).format(**inits) initStr += (" flip: {flip},\n" "}});\n\n").format(flip=boolConverter[inits['flip'].val]) buff.writeIndentedLines(initStr)
def test_Py2js_Expression2js(self): """Test that converts a short expression (e.g. a Component Parameter) Python to JS""" input = [ 'sin(t)', 'cos(t)', 'tan(t)', 'pi', 'rand', 'random', 't*5', '(3, 4)', '(5*-2)', '(1,(2,3))', '2*(2, 3)', '[1, (2*2)]', '(.7, .7)', '(-.7, .7)', '[-.7, -.7]', '[-.7, (-.7 * 7)]' ] output = [ 'Math.sin(t)', 'Math.cos(t)', 'Math.tan(t)', 'Math.PI', 'Math.random', 'Math.random', '(t * 5)', '[3, 4]', '(5 * (- 2))', '[1, [2, 3]]', '(2 * [2, 3])', '[1, (2 * 2)]', '[0.7, 0.7]', '[(- 0.7), 0.7]', '[(- 0.7), (- 0.7)]', '[(- 0.7), ((- 0.7) * 7)]' ] for idx, expr in enumerate(input): # check whether direct match or at least a match when spaces removed assert (py2js.expression2js(expr) == output[idx] or py2js.expression2js(expr).replace( " ", "") == output[idx].replace(" ", ""))
def test_Py2js_Expression2js(self): """Test that converts a short expression (e.g. a Component Parameter) Python to JS""" input = ['sin(t)', 'cos(t)', 'tan(t)', 'pi', 'rand', 'random', 't*5', '(3, 4)', '(5*-2)', '(1,(2,3))', '2*(2, 3)', '[1, (2*2)]', '(.7, .7)', '(-.7, .7)', '[-.7, -.7]', '[-.7, (-.7 * 7)]'] output = ['Math.sin(t)', 'Math.cos(t)', 'Math.tan(t)', 'Math.PI', 'Math.random', 'Math.random', '(t * 5)', '[3, 4]', '(5 * (- 2))', '[1, [2, 3]]', '(2 * [2, 3])', '[1, (2 * 2)]', '[0.7, 0.7]', '[(- 0.7), 0.7]', '[(- 0.7), (- 0.7)]', '[(- 0.7), ((- 0.7) * 7)]'] for idx, expr in enumerate(input): # check whether direct match or at least a match when spaces removed assert (py2js.expression2js(expr) == output[idx] or py2js.expression2js(expr).replace(" ", "") == output[idx].replace(" ", ""))
def writeInitCodeJS(self, buff): inits = getInitVals(self.params) for param in inits: if inits[param].val in ['', None, 'None', 'none']: inits[param].val = 'undefined' boolConverter = {False: 'false', True: 'true'} sliderStyles = { 'slider': 'SLIDER', '()': 'RATING', 'rating': 'RATING', 'radio': 'RADIO', 'labels45': 'LABELS_45', 'whiteOnBlack': 'WHITE_ON_BLACK', 'triangleMarker': 'TRIANGLE_MARKER' } # If no style given, set default 'rating' as list if len(inits['styles'].val) == 0: inits['styles'].val = ['rating'] # reformat styles for JS inits['styles'].val = ', '.join([ "visual.Slider.Style.{}".format(sliderStyles[style]) for style in inits['styles'].val ]) # add comma so is treated as tuple in py2js and converted to list, as required inits['styles'].val += ',' inits['styles'].val = py2js.expression2js(inits['styles'].val) # build up an initialization string for Slider(): initStr = ( "{name} = new visual.Slider({{\n" " win: psychoJS.window, name: '{name}',\n" " size: {size}, pos: {pos},\n" " labels: {labels}, ticks: {ticks},\n" " granularity: {granularity}, style: {styles},\n" " color: new util.Color({color}), \n" " fontFamily: {font}, bold: true, italic: false, \n").format( **inits) initStr += (" flip: {flip},\n" "}});\n\n").format(flip=boolConverter[inits['flip'].val]) buff.writeIndentedLines(initStr)
def writeInitCodeJS(self, buff): inits = getInitVals(self.params) for param in inits: if inits[param].val in ['', None, 'None', 'none']: inits[param].val = 'undefined' boolConverter = {False: 'false', True: 'true'} sliderStyles = {'slider': 'SLIDER', '()': 'RATING', 'rating': 'RATING', 'radio': 'RADIO', 'labels45': 'LABELS_45', 'whiteOnBlack': 'WHITE_ON_BLACK', 'triangleMarker': 'TRIANGLE_MARKER'} # If no style given, set default 'rating' as list if len(inits['styles'].val) == 0: inits['styles'].val = ['rating'] # reformat styles for JS inits['styles'].val = ', '.join(["visual.Slider.Style.{}". format(sliderStyles[style]) for style in inits['styles'].val]) # add comma so is treated as tuple in py2js and converted to list, as required inits['styles'].val += ',' inits['styles'].val = py2js.expression2js(inits['styles'].val) # build up an initialization string for Slider(): initStr = ("{name} = new visual.Slider({{\n" " win: psychoJS.window, name: '{name}',\n" " size: {size}, pos: {pos},\n" " labels: {labels}, ticks: {ticks},\n" " granularity: {granularity}, style: {styles},\n" " color: new util.Color({color}), \n" " fontFamily: {font}, bold: true, italic: false, \n" ).format(**inits) initStr += (" flip: {flip},\n" "}});\n\n").format(flip=boolConverter[inits['flip'].val]) buff.writeIndentedLines(initStr)
def getInitVals(params, target="PsychoPy"): """Works out a suitable initial value for a parameter (e.g. to go into the __init__ of a stimulus object, avoiding using a variable name if possible """ inits = copy.deepcopy(params) for name in params: if target == "PsychoJS": # convert (0,0.5) to [0,0.5] but don't convert "rand()" to "rand[]" and don't convert text valStr = str(inits[name].val).strip() if valStr.startswith("(") and valStr.endswith( ")") and name != 'text': inits[name].val = py2js.expression2js(inits[name].val) # filenames (e.g. for image) need to be loaded from resources if name in ["sound"]: val = str(inits[name].val) if val not in [None, 'None', 'none', '']: inits[name].val = ( "psychoJS.resourceManager.getResource({})".format( inits[name])) inits[name].valType = 'code' if not hasattr(inits[name], 'updates'): # might be settings parameter instead continue # value should be None (as code) elif inits[name].val in [None, 'None', 'none', '']: if name in ['text']: inits[name].val = None inits[name].valType = 'extendedStr' else: inits[name].val = 'None' inits[name].valType = 'code' # is constant so don't touch the parameter value elif inits[name].updates in ['constant', None, 'None']: continue # things that are constant don't need handling # is changing so work out a reasonable default elif name in ['pos', 'fieldPos']: inits[name].val = '[0,0]' inits[name].valType = 'code' elif name in [ 'color', 'foreColor', 'borderColor', 'lineColor', 'fillColor' ]: inits[name].val = 'white' inits[name].valType = 'str' elif name in [ 'ori', 'sf', 'size', 'height', 'letterHeight', 'lineWidth', 'phase', 'opacity', 'volume', # sounds 'coherence', 'nDots', 'fieldSize', 'dotSize', 'dotLife', 'dir', 'speed', 'contrast', 'moddepth', 'envori', 'envphase', 'envsf', 'noiseClip', 'noiseBWO', 'noiseFilterUpper', 'noiseFilterLower', 'noiseBaseSf', 'noiseBW', 'noiseElementSize', 'noiseFilterOrder', 'noiseFractalPower' ]: inits[name].val = "1.0" inits[name].valType = 'code' elif name in ['image', 'mask', 'envelope', 'carrier']: inits[name].val = "sin" inits[name].valType = 'str' elif name == 'texture resolution': inits[name].val = "128" inits[name].valType = 'code' elif name == 'colorSpace': inits[name].val = "rgb" inits[name].valType = 'str' elif name == 'font': inits[name].val = "Arial" inits[name].valType = 'str' elif name == 'units': inits[name].val = "norm" inits[name].valType = 'str' elif name == 'text': inits[name].val = "" inits[name].valType = 'str' elif name == 'flip': inits[name].val = "" inits[name].valType = 'str' elif name == 'sound': inits[name].val = "A" inits[name].valType = 'str' elif name == 'blendmode': inits[name].val = "avg" inits[name].valType = 'str' elif name == 'beat': inits[name].val = "False" inits[name].valType = 'str' elif name == 'noiseImage': inits[name].val = "None" inits[name].valType = 'str' elif name == 'noiseType': inits[name].val = 'Binary' inits[name].valType = 'str' elif name == 'marker_label': inits[name].val = 'Label' inits[name].valType = 'str' elif name == 'marker_value': inits[name].val = 'Value' inits[name].valType = 'str' elif name == 'buttonRequired': inits[name].val = "True" inits[name].valType = 'code' elif name == 'vertices': inits[ name].val = "[[-0.5,-0.5], [-0.5, 0.5], [0.5, 0.5], [0.5, -0.5]]" inits[name].valType = 'code' else: print("I don't know the appropriate default value for a '%s' " "parameter. Please email the mailing list about this error" % name) return inits
def getInitVals(params, target="PsychoPy"): """Works out a suitable initial value for a parameter (e.g. to go into the __init__ of a stimulus object, avoiding using a variable name if possible """ inits = copy.deepcopy(params) for name in params: if target == "PsychoJS": # convert (0,0.5) to [0,0.5] but don't convert "rand()" to "rand[]" valStr = str(inits[name].val).strip() if valStr.startswith("(") and valStr.endswith(")"): inits[name].val = py2js.expression2js(inits[name].val) # filenames (e.g. for image) need to be loaded from resources if name in ["sound"]: val = str(inits[name].val) if val not in [None, 'None', 'none', '']: inits[name].val = ("psychoJS.resourceManager.getResource({})" .format(inits[name])) inits[name].valType = 'code' if not hasattr(inits[name], 'updates'): # might be settings parameter instead continue # value should be None (as code) elif inits[name].val in [None, 'None', 'none', '']: inits[name].val = 'None' inits[name].valType = 'code' # is constant so don't touch the parameter value elif inits[name].updates in ['constant', None, 'None']: continue # things that are constant don't need handling # is changing so work out a reasonable default elif name in ['pos', 'fieldPos']: inits[name].val = '[0,0]' inits[name].valType = 'code' elif name is 'color': inits[name].val = 'white' inits[name].valType = 'str' elif name in ['ori', 'sf', 'size', 'height', 'letterHeight', 'lineColor', 'fillColor', 'phase', 'opacity', 'volume', # sounds 'coherence', 'nDots', 'fieldSize', 'dotSize', 'dotLife', 'dir', 'speed', 'contrast', 'moddepth', 'envori', 'envphase', 'envsf', 'noiseClip', 'noiseBWO', 'noiseFilterUpper', 'noiseFilterLower', 'noiseBaseSf', 'noiseBW', 'noiseElementSize', 'noiseFilterOrder', 'noiseFractalPower']: inits[name].val = "1.0" inits[name].valType = 'code' elif name in ['image', 'mask', 'envelope', 'carrier']: inits[name].val = "sin" inits[name].valType = 'str' elif name == 'texture resolution': inits[name].val = "128" inits[name].valType = 'code' elif name == 'colorSpace': inits[name].val = "rgb" inits[name].valType = 'str' elif name == 'font': inits[name].val = "Arial" inits[name].valType = 'str' elif name == 'units': inits[name].val = "norm" inits[name].valType = 'str' elif name == 'text': inits[name].val = "default text" inits[name].valType = 'str' elif name == 'flip': inits[name].val = "" inits[name].valType = 'str' elif name == 'sound': inits[name].val = "A" inits[name].valType = 'str' elif name == 'blendmode': inits[name].val = "avg" inits[name].valType = 'str' elif name == 'beat': inits[name].val = "False" inits[name].valType = 'str' elif name == 'noiseImage': inits[name].val = "None" inits[name].valType = 'str' elif name == 'noiseType': inits[name].val = 'Binary' inits[name].valType = 'str' else: print("I don't know the appropriate default value for a '%s' " "parameter. Please email the mailing list about this error" % name) return inits