def METHOD_NAME(scene_func):
    @wraps(scene_func)
    def func_wrapper(idict=None, **extra_args):
        if idict is None:
            idict = {}
        elif isinstance(idict, SceneCfg):
            idict = idict.as_dict()
        scene_cfg = SceneCfg(**idict)
        scene = scene_func(scene_cfg, **extra_args)
        odict = scene_cfg.as_dict()
        odict["scene"] = scene
        return odict
    # Construct widgets specs
    widgets_specs = []
    func_specs = inspect.getfullargspec(scene_func)
    if func_specs.defaults:
        nb_optionnals = len(func_specs.defaults)
        for i, key in enumerate(func_specs.args[-nb_optionnals:]):
            # Set controller defaults according to the function prototype
            control = controls.get(key)
            if control is not None:
                default = func_specs.defaults[i]
                ctl_id = control.__class__.__name__
                ctl_data = control._asdict()
                widgets_specs.append((key, default, ctl_id, ctl_data))
    # Transfers the widget specs to the UI.
    # We could use the return value but it's better if the user can still
    # call its decorated scene function transparently inside his own code
    # without getting garbage along the return value.
    func_wrapper.widgets_specs = widgets_specs
    # Flag the scene as a scene function so it's registered in the UI.
    func_wrapper.iam_a_ngl_scene_func = True
    return func_wrapper