Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Events are only working when passed an argument #203

Open
berinhard opened this issue Nov 9, 2021 · 1 comment
Open

Events are only working when passed an argument #203

berinhard opened this issue Nov 9, 2021 · 1 comment

Comments

@berinhard
Copy link
Owner

Event handler functions such as keyPressed or mouseDragged from p5.js doesn't require any parameter to work. But pyp5js is only working if the event paremeter is present in the function definition.

So, for example, running the following code with the demo editor raises an TypeError as the traceback describes:

Sample code

def setup():
    createCanvas(200, 200)

def draw():
    background(200)
    diameter = sin(frameCount / 60) * 50 + 50
    fill("blue")
    ellipse(100, 100, diameter, diameter)

def keyPressed():
    print(key)

Traceback error

Uncaught PythonError: Traceback (most recent call last):
  File "<exec>", line 1595, in wrapper
  File "<exec>", line 1583, in pre_draw
TypeError: keyPressed() takes 0 positional arguments but 1 was given

But, if we change the keyPressed to receive an argument, it works. So, the pyodide mode must be updated to not require this parameter in order for event functions to work.

@sidharth-04
Copy link

I have managed to find a work around for the issue by making a small modification to the wrapperContent constant in the target_sketch.js file. I modify the global_p5_injection function to:

def global_p5_injection(p5_sketch):
    """
    Injects the p5js's skecth instance as a global variable to setup and draw functions
    """

    def decorator(f, event_function=False):
        def wrapper(*args, **kwargs):
            global _P5_INSTANCE
            _P5_INSTANCE = p5_sketch
            try:
                temp_output = pre_draw(_P5_INSTANCE, f, *args, **kwargs)
                return temp_output
            except:
                traceback_str = traceback.format_exc()
                log_error_to_console(traceback_str)
        
        def event_wrapper(event):
            wrapper()

        if event_function:
            return event_wrapper
        return wrapper

    return decorator

When the event_function parameter is passed, the decorator wraps the user's code in an outer function which accepts an argument (which p5 seems to expect). The start_p5 function is modified as follows to set event functions:

for f_name in [f for f in event_function_names if event_functions.get(f, None)]:
    func = event_functions[f_name]
    event_func = global_p5_injection(window.instance)(func, True)
    setattr(window.instance, f_name, event_func)

This allows the user to define event functions such as keyPressed and mouseClicked without the unnecessary argument in their code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants