Beispiel #1
0
    def __init__(self, parent, bot, title=None):
        self.parent = parent
        self.bot = bot

        self.var_listener = VarListener(self)

        self.window = Gtk.Window()
        self.window.set_destroy_with_parent(True)
        self.window.connect("destroy", self.do_quit)

        if os.path.isfile(ICON_FILE):
            self.window.set_icon_from_file(ICON_FILE)

        self.container = Gtk.VBox(homogeneous=True, spacing=20)

        # set up sliders
        self.widgets = {}
        self.vars = {}
        self.add_variables()

        self.window.add(self.container)
        self.window.set_size_request(400, 35 * len(list(self.widgets.keys())))
        self.window.show_all()

        if title:
            self.window.set_title(title)
Beispiel #2
0
    def __init__(self, parent, bot, title = None):
        self.parent = parent
        self.bot = bot

        self.var_listener = VarListener(self)

        self.window = Gtk.Window()
        self.window.set_destroy_with_parent(True)
        self.window.connect("destroy", self.do_quit)

        if os.path.isfile(ICON_FILE):
            self.window.set_icon_from_file( ICON_FILE )

        self.container = Gtk.VBox(homogeneous=True, spacing=20)

        # set up sliders
        self.widgets = {}
        self.vars = {}
        self.add_variables()

        self.window.add(self.container)
        self.window.set_size_request(400, 35*len(self.widgets.keys()))
        self.window.show_all()

        if title:
            self.window.set_title(title)
Beispiel #3
0
    def _run_frame(self, executor, limit=False, iteration=0):
        """ Run single frame of the bot

        :param source_or_code: path to code to run, or actual code.
        :param limit: Time a frame should take to run (float - seconds)
        """
        #
        # Gets a bit complex here...
        #
        # Nodebox (which we are trying to be compatible with) supports two
        # kinds of bot 'dynamic' which has a 'draw' function and non dynamic
        # which doesn't have one.
        #
        # Dynamic bots:
        #
        # First run:
        # run body and 'setup' if it exists, then 'draw'
        #
        # Later runs:
        # run 'draw'
        #
        # Non Dynamic bots:
        #
        # Just have a 'body' and run once...
        #
        # UNLESS...  a 'var' is changed, then run it again.
        #
        #
        # Livecoding:
        #
        # Code can be 'known_good' or 'tenous' (when it has been edited).
        #
        # If code is tenous and an exception occurs, attempt to roll
        # everything back.
        #
        # Livecoding and vars
        #
        # If vars are added / removed or renamed then attempt to update
        # the GUI

        start_time = time()
        if iteration != 0 and self._speed != 0:
            self._canvas.reset_canvas()
        self._set_dynamic_vars()
        if iteration == 0:
            # First frame
            executor.run()
            # run setup and draw
            # (assume user hasn't live edited already)
            executor.ns['setup']()
            executor.ns['draw']()
            self._canvas.flush(self._frame)
        else:
            # Subsequent frames
            if self._dynamic:
                if self._speed != 0: # speed 0 is paused, so do nothing
                    with executor.run_context() as (known_good, source, ns):
                        # Code in main block may redefine 'draw'
                        if not known_good:
                            executor.reload_functions()
                            with VarListener.batch(self._vars, self._oldvars, ns):
                                self._oldvars.clear()

                                # Re-run the function body - ideally this would only
                                # happen if the body had actually changed
                                # - Or perhaps if the line included a variable declaration
                                exec source in ns

                        ns['draw']()
                        self._canvas.flush(self._frame)
            else:
                # Non "dynamic" bots
                #
                # TODO - This part is overly complex, before live-coding it
                #        was just exec source in ns ... have to see if it
                #        can be simplified again.
                #
                with executor.run_context() as (known_good, source, ns):
                    if not known_good:
                        executor.reload_functions()
                        with VarListener.batch(self._vars, self._oldvars, ns):
                            self._oldvars.clear()

                            # Re-run the function body - ideally this would only
                            # happen if the body had actually changed
                            # - Or perhaps if the line included a variable declaration
                            exec source in ns
                    else:
                        exec source in ns

                    self._canvas.flush(self._frame)
        if limit:
            self._frame_limit(start_time)

        # Can set speed to go backwards using the shell if you really want
        # or pause by setting speed == 0
        if self._speed > 0:
            self._frame += 1
        elif self._speed < 0:
            self._frame -= 1
Beispiel #4
0
    def _run_frame(self, executor, limit=False, iteration=0):
        """ Run single frame of the bot

        :param source_or_code: path to code to run, or actual code.
        :param limit: Time a frame should take to run (float - seconds)
        """
        #
        # Gets a bit complex here...
        #
        # Nodebox (which we are trying to be compatible with) supports two
        # kinds of bot 'dynamic' which has a 'draw' function and non dynamic
        # which doesn't have one.
        #
        # Dynamic bots:
        #
        # First run:
        # run body and 'setup' if it exists, then 'draw'
        #
        # Later runs:
        # run 'draw'
        #
        # Non Dynamic bots:
        #
        # Just have a 'body' and run once...
        #
        # UNLESS...  a 'var' is changed, then run it again.
        #
        #
        # Livecoding:
        #
        # Code can be 'known_good' or 'tenous' (when it has been edited).
        #
        # If code is tenous and an exception occurs, attempt to roll
        # everything back.
        #
        # Livecoding and vars
        #
        # If vars are added / removed or renamed then attempt to update
        # the GUI

        start_time = time()
        if iteration != 0 and self._speed != 0:
            self._canvas.reset_canvas()
        self._set_dynamic_vars()
        if iteration == 0:
            # First frame
            executor.run()
            # run setup and draw
            # (assume user hasn't live edited already)
            executor.ns['setup']()
            executor.ns['draw']()
            self._canvas.flush(self._frame)
        else:
            # Subsequent frames
            if self._dynamic:
                if self._speed != 0:  # speed 0 is paused, so do nothing
                    with executor.run_context() as (known_good, source, ns):
                        # Code in main block may redefine 'draw'
                        if not known_good:
                            executor.reload_functions()
                            with VarListener.batch(self._vars, self._oldvars,
                                                   ns):
                                self._oldvars.clear()

                                # Re-run the function body - ideally this would only
                                # happen if the body had actually changed
                                # - Or perhaps if the line included a variable declaration
                                exec(source, ns)

                        ns['draw']()
                        self._canvas.flush(self._frame)
            else:
                # Non "dynamic" bots
                #
                # TODO - This part is overly complex, before live-coding it
                #        was just exec source in ns ... have to see if it
                #        can be simplified again.
                #
                with executor.run_context() as (known_good, source, ns):
                    if not known_good:
                        executor.reload_functions()
                        with VarListener.batch(self._vars, self._oldvars, ns):
                            self._oldvars.clear()

                            # Re-run the function body - ideally this would only
                            # happen if the body had actually changed
                            # - Or perhaps if the line included a variable declaration
                            exec(source, ns)
                    else:
                        exec(source, ns)

                    self._canvas.flush(self._frame)
        if limit:
            self._frame_limit(start_time)

        # Can set speed to go backwards using the shell if you really want
        # or pause by setting speed == 0
        if self._speed > 0:
            self._frame += 1
        elif self._speed < 0:
            self._frame -= 1
Beispiel #5
0
class VarWindow(object):
    def __init__(self, parent, bot, title = None):
        self.parent = parent
        self.bot = bot

        self.var_listener = VarListener(self)

        self.window = Gtk.Window()
        self.window.set_destroy_with_parent(True)
        self.window.connect("destroy", self.do_quit)

        if os.path.isfile(ICON_FILE):
            self.window.set_icon_from_file( ICON_FILE )

        self.container = Gtk.VBox(homogeneous=True, spacing=20)

        # set up sliders
        self.widgets = {}
        self.vars = {}
        self.add_variables()

        self.window.add(self.container)
        self.window.set_size_request(400, 35*len(self.widgets.keys()))
        self.window.show_all()

        if title:
            self.window.set_title(title)
        ## Gtk.main()

    def add_variables(self):
        """
        Add all widgets to specified vbox
        :param container:
        :return:
        """
        for v in sorted(self.bot._vars.values()):
            self.add_variable(v)

    def add_variable(self, v):
        if v.type is NUMBER:
            self.widgets[v.name] = self.add_number(v)
        elif v.type is TEXT:
            self.widgets[v.name] = self.add_text(v)
        elif v.type is BOOLEAN:
            self.widgets[v.name] = self.add_boolean(v)
        elif v.type is BUTTON:
            self.widgets[v.name] = self.add_button(v)
        else:
            raise ValueError('Unknown variable type.')
        self.vars[v.name] = v

    def add_number(self, v):
        # create a slider for each var
        sliderbox = Gtk.HBox(homogeneous=False, spacing=0)
        label = Gtk.Label(pretty_name(v.name))
        sliderbox.pack_start(label, False, True, 20)

        if v.min != v.max:
            step = v.step
        else:
            step = 0

        if v.max - v.min > 2:
            adj = Gtk.Adjustment(value=v.value, lower=v.min, upper=v.max, step_incr=step, page_incr=2, page_size=1)
        else:
            adj = Gtk.Adjustment(value=v.value, lower=v.min, upper=v.max, step_incr=step)
        adj.connect("value_changed", self.widget_changed, v)
        hscale = Gtk.HScale(adjustment=adj)
        hscale.set_value_pos(Gtk.PositionType.RIGHT)
        hscale.set_value(v.value)
        sliderbox.pack_start(hscale, True, True, 0)
        self.container.pack_start(sliderbox, True, True, 0)

        return hscale

    def add_text(self, v):
        textcontainer = Gtk.HBox(homogeneous=False, spacing=0)
        label = Gtk.Label(pretty_name(v.name))
        textcontainer.pack_start(label, False, True, 20)

        entry = Gtk.Entry()
        entry.set_text(v.value)
        entry.connect("changed", self.widget_changed, v)
        textcontainer.pack_start(entry, True, True, 0)
        self.container.pack_start(textcontainer, True, True, 0)

        return entry

    def add_boolean(self, v):
        buttoncontainer = Gtk.HBox(homogeneous=False, spacing=0)
        button = Gtk.CheckButton(label=pretty_name(v.name))
        button.set_active(v.value)
        # we send the state of the button to the callback method
        button.connect("toggled", self.widget_changed, v)

        buttoncontainer.pack_start(button, True, True, 0)
        self.container.pack_start(buttoncontainer, True, True, 0)

        return button

    def add_button(self, v):
        buttoncontainer = Gtk.HBox(homogeneous=False, spacing=0)
        # in buttons, the varname is the function, so we use __name__

        func_name = v.name

        def call_func(*args):
            func = self.bot._namespace[func_name]
            func()

        button = Gtk.Button(label=pretty_name(v.name))
        button.connect("clicked", call_func, None)
        buttoncontainer.pack_start(button, True, True, 0)
        self.container.pack_start(buttoncontainer, True, True, 0)

        return button

    def do_destroy(self, widget):
        self.var_listener.remove()

    def do_quit(self, widget):
        pass

    def update_var(self, name, value):
        """
        :return: success, err_msg_if_failed
        """
        widget = self.widgets.get(name)
        if widget is None:
            return False, 'No widget found matching, {}'.format(name)

        try:
            if isinstance(widget, Gtk.CheckButton):
                widget.set_active(value)
                return True, widget.get_active()
            elif isinstance(widget, Gtk.Entry):
                widget.set_text(value)
                return True, widget.get_text()
            else:
                widget.set_value(value)
                return True, widget.get_value()
        except Exception as e:
            return False, str(e)

    def widget_changed(self, widget, v):
        ''' Called when a slider is adjusted. '''
        # set the appropriate bot var
        if v.type is NUMBER:
            self.bot._namespace[v.name] = widget.get_value()
            self.bot._vars[v.name].value = widget.get_value()  ## Not sure if this is how to do this - stu
            publish_event(EVENT_VARIABLE_UPDATED, v) # pretty dumb for now
        elif v.type is BOOLEAN:
            self.bot._namespace[v.name] = widget.get_active()
            self.bot._vars[v.name].value = widget.get_active()  ## Not sure if this is how to do this - stu
            publish_event(EVENT_VARIABLE_UPDATED, v) # pretty dumb for now
        elif v.type is TEXT:
            self.bot._namespace[v.name] = widget.get_text()
            self.bot._vars[v.name].value = widget.get_text()  ## Not sure if this is how to do this - stu
            publish_event(EVENT_VARIABLE_UPDATED, v) # pretty dumb for now

    def var_added(self, v):
        """
        var was added in the bot while it ran, possibly
        by livecoding

        :param v:
        :return:
        """
        self.add_variable(v)

        self.window.set_size_request(400, 35*len(self.widgets.keys()))
        self.window.show_all()

    def var_deleted(self, v):
        """
        var was added in the bot

        :param v:
        :return:
        """
        widget = self.widgets[v.name]

        # widgets are all in a single container ..
        parent = widget.get_parent()
        self.container.remove(parent)
        del self.widgets[v.name]

        self.window.set_size_request(400, 35*len(self.widgets.keys()))
        self.window.show_all()

    def var_updated(self, v):
        pass
Beispiel #6
0
class VarWindow(object):
    def __init__(self, parent, bot, title=None):
        self.parent = parent
        self.bot = bot

        self.var_listener = VarListener(self)

        self.window = Gtk.Window()
        self.window.set_destroy_with_parent(True)
        self.window.connect("destroy", self.do_quit)

        if os.path.isfile(ICON_FILE):
            self.window.set_icon_from_file(ICON_FILE)

        self.container = Gtk.VBox(homogeneous=True, spacing=20)

        # set up sliders
        self.widgets = {}
        self.vars = {}
        self.add_variables()

        self.window.add(self.container)
        self.window.set_size_request(400, 35 * len(list(self.widgets.keys())))
        self.window.show_all()

        if title:
            self.window.set_title(title)

    def add_variables(self):
        """
        Add all widgets to specified vbox
        :param container:
        :return:
        """
        for k, v in list(self.bot._vars.items()):
            if not hasattr(v, 'type'):
                raise AttributeError(
                    '%s is not a Shoebot Variable - see https://shoebot.readthedocs.io/en/latest/commands.html#dynamic-variables'
                    % k)
            self.add_variable(v)

    def add_variable(self, v):
        if v.type is NUMBER:
            self.widgets[v.name] = self.add_number(v)
        elif v.type is TEXT:
            self.widgets[v.name] = self.add_text(v)
        elif v.type is BOOLEAN:
            self.widgets[v.name] = self.add_boolean(v)
        elif v.type is BUTTON:
            self.widgets[v.name] = self.add_button(v)
        else:
            raise ValueError('Unknown variable type.')
        self.vars[v.name] = v

    def add_number(self, v):
        # create a slider for each var
        sliderbox = Gtk.HBox(homogeneous=False, spacing=0)
        label = Gtk.Label(pretty_name(v.name))
        sliderbox.pack_start(label, False, True, 20)

        if v.min != v.max:
            step = v.step
        else:
            step = 0.0

        if v.max - v.min > 2:
            adj = Gtk.Adjustment(v.value,
                                 v.min,
                                 v.max,
                                 step,
                                 page_incr=2,
                                 page_size=1)
        else:
            adj = Gtk.Adjustment(v.value, v.min, v.max, step)
        adj.connect("value_changed", self.widget_changed, v)
        hscale = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL,
                           adjustment=adj)
        hscale.set_value_pos(Gtk.PositionType.RIGHT)
        if (v.max - v.min) / (step or 0.1) > 10:
            hscale.set_digits(2)
        sliderbox.pack_start(hscale, True, True, 0)
        self.container.pack_start(sliderbox, True, True, 0)
        return hscale

    def add_text(self, v):
        textcontainer = Gtk.HBox(homogeneous=False, spacing=0)
        label = Gtk.Label(pretty_name(v.name))
        textcontainer.pack_start(label, False, True, 20)

        entry = Gtk.Entry()
        entry.set_text(v.value)
        entry.connect("changed", self.widget_changed, v)
        textcontainer.pack_start(entry, True, True, 0)
        self.container.pack_start(textcontainer, True, True, 0)

        return entry

    def add_boolean(self, v):
        buttoncontainer = Gtk.HBox(homogeneous=False, spacing=0)
        button = Gtk.CheckButton(label=pretty_name(v.name))
        button.set_active(v.value)
        # we send the state of the button to the callback method
        button.connect("toggled", self.widget_changed, v)

        buttoncontainer.pack_start(button, True, True, 0)
        self.container.pack_start(buttoncontainer, True, True, 0)

        return button

    def add_button(self, v):
        buttoncontainer = Gtk.HBox(homogeneous=False, spacing=0)
        # in buttons, the varname is the function, so we use __name__

        func_name = v.name

        def call_func(*args):
            func = self.bot._namespace[func_name]
            func()

        button = Gtk.Button(label=pretty_name(v.name))
        button.connect("clicked", call_func, None)
        buttoncontainer.pack_start(button, True, True, 0)
        self.container.pack_start(buttoncontainer, True, True, 0)

        return button

    def do_destroy(self, widget):
        self.var_listener.remove()

    def do_quit(self, widget):
        pass

    def update_var(self, name, value):
        """
        :return: success, err_msg_if_failed
        """
        widget = self.widgets.get(name)
        if widget is None:
            return False, 'No widget found matching, {}'.format(name)

        try:
            if isinstance(widget, Gtk.CheckButton):
                widget.set_active(value)
                return True, widget.get_active()
            elif isinstance(widget, Gtk.Entry):
                widget.set_text(value)
                return True, widget.get_text()
            else:
                widget.set_value(value)
                return True, widget.get_value()
        except Exception as e:
            return False, str(e)

    def widget_changed(self, widget, v):
        ''' Called when a slider is adjusted. '''
        # set the appropriate bot var
        if v.type is NUMBER:
            self.bot._namespace[v.name] = widget.get_value()
            self.bot._vars[v.name].value = widget.get_value(
            )  ## Not sure if this is how to do this - stu
            publish_event(VARIABLE_UPDATED_EVENT, v)  # pretty dumb for now
        elif v.type is BOOLEAN:
            self.bot._namespace[v.name] = widget.get_active()
            self.bot._vars[v.name].value = widget.get_active(
            )  ## Not sure if this is how to do this - stu
            publish_event(VARIABLE_UPDATED_EVENT, v)  # pretty dumb for now
        elif v.type is TEXT:
            self.bot._namespace[v.name] = widget.get_text()
            self.bot._vars[v.name].value = widget.get_text(
            )  ## Not sure if this is how to do this - stu
            publish_event(VARIABLE_UPDATED_EVENT, v)  # pretty dumb for now

    def var_added(self, v):
        """
        var was added in the bot while it ran, possibly
        by livecoding

        :param v:
        :return:
        """
        self.add_variable(v)

        self.window.set_size_request(400, 35 * len(list(self.widgets.keys())))
        self.window.show_all()

    def var_deleted(self, v):
        """
        var was added in the bot

        :param v:
        :return:
        """
        widget = self.widgets[v.name]

        # widgets are all in a single container ..
        parent = widget.get_parent()
        self.container.remove(parent)
        del self.widgets[v.name]

        self.window.set_size_request(400, 35 * len(list(self.widgets.keys())))
        self.window.show_all()

    def var_updated(self, v):
        pass