Esempio n. 1
0
 def update(self, input_called=-1, output_called=-1):
     Debugger.debug('update in', self.parent_node.title, 'on input',
                    input_called)
     try:
         self.update_event(input_called)
     except Exception as e:
         Debugger.debug('EXCEPTION IN', self.parent_node.title, 'NI:', e)
Esempio n. 2
0
    def get_var(self, name):
        Debugger.debug('getting variable with name:', name)

        for v in self.variables:
            if v.name == name:
                return v
        return None
Esempio n. 3
0
    def remove_node_instance(self, ni):
        ni.about_to_remove_from_scene()  # to stop running threads

        self.scene().removeItem(ni)

        Debugger.debug('calling ni removed')
        self.all_node_instances.remove(ni)
Esempio n. 4
0
    def create_new_input(self,
                         type_,
                         label,
                         widget_type='',
                         widget_name='',
                         widget_pos='under',
                         pos=-1):
        """Creates and adds a new input. Handy for subclasses."""
        Debugger.debug('create_new_input called with widget pos:', widget_pos)
        pi = PortInstance(self,
                          'input',
                          type_,
                          label,
                          widget_type=widget_type,
                          widget_name=widget_name,
                          widget_pos=widget_pos)
        if pos == -1:
            self.inputs.append(pi)
        else:
            if pos == -1:
                self.inputs.insert(0, pi)
            else:
                self.inputs.insert(pos, pi)
        if self.scene():
            self.add_input_to_scene(pi)

        if not self.initializing:
            self.update_shape()
Esempio n. 5
0
    def import_nodes_package(self, file_path):
        j_str = ''
        try:
            f = open(file_path)
            j_str = f.read()
            f.close()
        except FileExistsError or FileNotFoundError:
            Debugger.debug('couldn\'t open file')
            return

        # don't import a package twice if it already has been imported
        filename = os.path.splitext(os.path.basename(file_path))
        if filename in self.package_names:
            return

        # Important: translate the package first (metacore files -> src code files)
        PackageTranslator = self.get_class_from_file(
            file_path='../Ryven_PackageTranslator',
            file_name='Ryven_PackageTranslator',
            class_name='PackageTranslator')
        package_translator = PackageTranslator(
            os.path.dirname(os.path.abspath(file_path)))

        self.parse_nodes(j_str,
                         package_path=os.path.dirname(file_path),
                         package_name=os.path.splitext(
                             os.path.basename(file_path))[0])  #

        self.package_names.append(filename)
Esempio n. 6
0
    def input(self, index):
        """Returns the value of a data input.
        If the input is connected, the value of the connected output is used:
        If not, the value of the widget is used."""

        Debugger.debug('input called in', self.parent_node.title, 'NI:', index)
        return self.inputs[index].get_val()
Esempio n. 7
0
    def create_new_input(self,
                         type_,
                         label,
                         widget_name=None,
                         widget_pos='under',
                         pos=-1,
                         config=None):
        """Creates and adds a new input. Handy for subclasses."""
        Debugger.debug('create_new_input called')
        pi = InputPortInstance(self,
                               type_,
                               label,
                               config_data=config,
                               widget_name=widget_name,
                               widget_pos=widget_pos)
        if pos < -1:
            pos += len(self.inputs)
        if pos == -1:
            self.inputs.append(pi)
            self.add_input_to_layout(pi)
        else:
            self.inputs.insert(pos, pi)
            self.insert_input_into_layout(pos, pi)

        if not self.initializing:
            self.update_shape()
            self.update()
Esempio n. 8
0
    def parse_nodes(self, j_str, package_path, package_name):
        """Parses the nodes from a node package in JSON format.
        Here, all the classes get imported and for every node a Node object with specific attribute values gets
        created."""

        import json

        # strict=False is necessary to allow 'control characters' like '\n' for newline when loading the json
        j_obj = json.loads(j_str, strict=False)

        Debugger.debug(j_obj['type'])
        if j_obj['type'] != 'Ryven nodes package' and j_obj[
                'type'] != 'vyScriptFP nodes package':  # old syntax
            return

        # package_title = j_obj['title']
        # package_description = j_obj['description']
        j_nodes_list = j_obj['nodes']

        num_nodes = len(j_nodes_list)
        for ni in range(num_nodes):
            j_node = j_nodes_list[ni]
            self.parse_node(j_node, package_name, package_path)

        Debugger.debug(len(self.custom_nodes), 'nodes imported')
Esempio n. 9
0
    def save_project(self, file_name):
        import json

        file = None
        try:
            if os.path.exists(file_name):
                os.remove(file_name)
            file = open(file_name, 'w')
        except FileNotFoundError:
            Debugger.debug('couldn\'t open file')
            return

        general_project_info_dict = {'type': 'Ryven project file'}

        scripts_data = []
        for script in self.scripts:
            scripts_data.append(script.get_json_data())

        whole_project_dict = {
            'general info': general_project_info_dict,
            'scripts': scripts_data
        }

        json_str = json.dumps(whole_project_dict)
        Debugger.debug(json_str)

        file.write(json_str)
        file.close()
Esempio n. 10
0
    def data_outputs_updated(self):
        """(outdated!) Sends update signals to all data outputs causing connected NIs to update."""

        Debugger.debug('updating data outputs in', self.parent_node.title)
        for o in self.outputs:
            if o.type_ == 'data':
                o.updated_val()
        Debugger.debug('data outputs in', self.parent_node.title, 'updated')
Esempio n. 11
0
    def tabletEvent(self, event):
        """tabletEvent gets called by stylus operations.
        LeftButton: std, no button pressed
        RightButton: upper button pressed"""

        # if in edit mode and not panning or starting a pan, pass on to std mouseEvent handlers above
        if self.stylus_mode == 'edit' and not self.panning and not \
                (event.type() == QTabletEvent.TabletPress and event.button() == Qt.RightButton):
            return  # let the mousePress/Move/Release-Events handle it

        scaled_event_pos: QPointF = event.posF() / self.current_scale

        if event.type() == QTabletEvent.TabletPress:
            self.ignore_mouse_event = True

            if event.button() == Qt.LeftButton:
                if self.stylus_mode == 'comment':
                    view_pos = self.mapToScene(self.viewport().pos())
                    new_drawing = self.create_and_place_drawing__cmd(
                        view_pos + scaled_event_pos,
                        config={
                            **self.stylus_modes_widget.get_pen_settings(), 'viewport pos':
                            view_pos
                        })
                    self.current_drawing = new_drawing
                    self.drawing = True
            elif event.button() == Qt.RightButton:
                self.panning = True
                self.pan_last_x = event.x()
                self.pan_last_y = event.y()

        elif event.type() == QTabletEvent.TabletMove:
            self.ignore_mouse_event = True
            if self.panning:
                self.pan(event.pos())

            elif event.pointerType() == QTabletEvent.Eraser:
                if self.stylus_mode == 'comment':
                    for i in self.items(event.pos()):
                        if find_type_in_object(i, DrawingObject):
                            self.remove_drawing(i)
                            break
            elif self.stylus_mode == 'comment' and self.drawing:
                if self.current_drawing.append_point(scaled_event_pos):
                    self.current_drawing.stroke_weights.append(
                        event.pressure())
                self.current_drawing.update()
                self.viewport().update()

        elif event.type() == QTabletEvent.TabletRelease:
            if self.panning:
                self.panning = False
            if self.stylus_mode == 'comment' and self.drawing:
                Debugger.debug('drawing obj finished')
                self.current_drawing.finished()
                self.current_drawing = None
                self.drawing = False
Esempio n. 12
0
    def tabletEvent(self, event):
        """tabletEvent gets called by stylus operations.
        LeftButton: std, no button pressed
        RightButton: upper button pressed"""

        # if in edit mode and not panning or starting a pan, pass on to std mouseEvent handlers above
        if self.stylus_mode == 'edit' and not self.panning and not \
                (event.type() == QTabletEvent.TabletPress and event.button() == Qt.RightButton):
            return  # let the mousePress/Move/Release-Events handle it

        if event.type() == QTabletEvent.TabletPress:
            self.tablet_press_pos = event.pos()
            self.ignore_mouse_event = True

            if event.button() == Qt.LeftButton:
                if self.stylus_mode == 'comment':
                    new_drawing = self.create_and_place_drawing__cmd(self.mapToScene(self.tablet_press_pos),
                                                                     config=self.stylus_modes_widget.get_pen_settings())
                    self.current_drawing = new_drawing
                    self.drawing = True
            elif event.button() == Qt.RightButton:
                self.panning = True
                self.pan_last_x = event.x()
                self.pan_last_y = event.y()

        elif event.type() == QTabletEvent.TabletMove:
            self.ignore_mouse_event = True
            if self.panning:
                self.pan(event.pos())

            elif event.pointerType() == QTabletEvent.Eraser:
                if self.stylus_mode == 'comment':
                    for i in self.items(event.pos()):
                        if find_type_in_object(i, DrawingObject):
                            self.remove_drawing(i)
                            break
            elif self.stylus_mode == 'comment' and self.drawing:

                mapped = self.mapToScene(QPoint(event.posF().x(), event.posF().y()))
                # rest = QPointF(event.posF().x()%1, event.posF().y()%1)
                # exact = QPointF(mapped.x()+rest.x()%1, mapped.y()+rest.y()%1)
                # TODO: use exact position (event.posF() ). Problem: mapToScene() only uses QPoint, not QPointF. The
                #  calculation above didn't work

                if self.current_drawing.try_to_append_point(mapped):
                    self.current_drawing.stroke_weights.append(event.pressure())
                self.current_drawing.update()
                self.viewport().update()

        elif event.type() == QTabletEvent.TabletRelease:
            if self.panning:
                self.panning = False
            if self.stylus_mode == 'comment' and self.drawing:
                Debugger.debug('drawing obj finished')
                self.current_drawing.finished()
                self.current_drawing = None
                self.drawing = False
Esempio n. 13
0
 def get_sorted_dict_matching_search(self, items_dict, text):
     indices_dict = {}
     for item, name in items_dict.items(
     ):  # the strings are already lowered here
         Debugger.debug(item, name, text)
         if name.__contains__(text):
             index = name.index(text)
             indices_dict[item] = index
     return {
         k: v
         for k, v in sorted(indices_dict.items(), key=lambda i: i[1])
     }
Esempio n. 14
0
    def set_val(self, val):
        """applies on INPUT; called NI internally"""
        Debugger.debug('setting value of', self.direction, 'port of',
                       self.parent_node_instance.parent_node.title,
                       'NodeInstance to', val)

        # note that val COULD be of object type and therefore already changed (because the original object did)
        self.val = val

        # if gen_data_on_request is set to true, all data will be required instead of actively forward propagated
        if not Algorithm.gen_data_on_request:
            self.updated_val()
Esempio n. 15
0
    def set_val(self, val):
        """applies on OUTPUT; called NI internally"""
        Debugger.debug('setting value of', self.direction, 'port of',
                       self.parent_node_instance.parent_node.title,
                       'NodeInstance to', val)

        # note that val COULD be of object type and therefore already changed (because the original object did)
        self.val = val

        # if algorithm mode would be exec flow, all data will be required instead of actively forward propagated
        if self.parent_node_instance.flow.algorithm_mode.mode_data_flow and \
                not self.parent_node_instance.initializing:
            self.updated_val()
Esempio n. 16
0
    def update(self, input_called=-1, output_called=-1):
        """This is the method used to activate a NodeInstance. Note that this signature shadows the update() method from
        QGraphicsItem used to graphically update a QGraphicsItem which can be accessed via
        QGraphicsItem.update(self)."""

        if Design.animations_enabled:
            self.animator.start()

        Debugger.debug('update in', self.parent_node.title, 'on input', input_called)
        try:
            self.update_event(input_called)
        except Exception as e:
            Debugger.debugerr('EXCEPTION IN', self.parent_node.title, 'NI:', e)
Esempio n. 17
0
    def add_package_button_clicked(self):
        file_names = \
            QFileDialog.getOpenFileNames(self, 'select package files', '../packages', 'Ryven Package(*.rpc)')[0]

        for file_name in file_names:
            try:
                f = open(file_name)
                f.close()
                self.file_paths.append(file_name)
            except FileNotFoundError:
                Debugger.debug('couldn\'t open file')

        self.rebuild_selected_packages_list_widget()
Esempio n. 18
0
    def set_val(self, val):
        """applies on INPUT; called NI internally"""
        Debugger.debug('setting value of', self.direction, 'port of',
                       self.parent_node_instance.parent_node.title,
                       'NodeInstance to', val)

        if self.val is val:  # no update if value didn't change
            return

        self.val = val
        self.gate.setToolTip(str(val))
        self.gate.update()
        self.updated_val()
Esempio n. 19
0
    def dropEvent(self, event):
        text = event.mimeData().text()
        item: QListWidgetItem = event.mimeData()
        Debugger.debug('drop received in Flow:', text)

        j_obj = None
        type = ''
        try:
            j_obj = json.loads(text)
            type = j_obj['type']
        except Exception:
            return

        if type == 'variable':
            self.show_node_choice_widget(event.pos(),  # only show get_var and set_var nodes
                                         [n for n in self.all_nodes if find_type_in_object(n, GetVariable_Node) or
                                          find_type_in_object(n, SetVariable_Node)])
Esempio n. 20
0
    def load_project_button_clicked(self):
        self.editor_startup_configuration['config'] = 'open project'
        import json

        file_name = QFileDialog.getOpenFileName(
            self, 'select project file', '../saves',
            'Ryven Project(*.rpo *.rypo)')[0]
        j_str = ''
        try:
            f = open(file_name)
            j_str = f.read()
            f.close()
        except FileNotFoundError:
            Debugger.debug('couldn\'t open file')
            return

        # strict=False has to be to allow 'control characters' like '\n' for newline when loading the json
        j_obj = json.loads(j_str, strict=False)

        if j_obj['general info']['type'] != 'Ryven project file':
            return

        # scan for all required packages
        packages = []
        package_file_paths = []

        scripts = j_obj['scripts']
        for script in scripts:
            flow = script['flow']
            for n in flow['nodes']:
                package = n['parent node package']
                if package != 'built in' and not packages.__contains__(
                        package):
                    packages.append(package)

        if len(packages) > 0:
            select_packages_dialog = SelectPackages_Dialog(self, packages)
            select_packages_dialog.exec_()
            package_file_paths = select_packages_dialog.file_paths

        self.editor_startup_configuration[
            'required packages'] = package_file_paths
        self.editor_startup_configuration['content'] = j_obj

        self.accept()
Esempio n. 21
0
    def import_nodes_package_from_file(self, file_path):
        j_str = ''
        try:
            f = open(file_path)
            j_str = f.read()
            f.close()
        except FileExistsError or FileNotFoundError:
            Debugger.debug('couldn\'t open file')
            return


        # Important: translate the package first (metacore files -> src code files)
        PackageTranslator = self.get_class_from_file(file_path='../pyScript_PackageTranslator',
                                                     file_name='pyScript_PackageTranslator',
                                                     class_name='PackageTranslator')
        package_translator = PackageTranslator(os.path.dirname(os.path.abspath(file_path)))


        self.parse_nodes(j_str, os.path.dirname(file_path), os.path.splitext(os.path.basename(file_path))[0])
Esempio n. 22
0
    def mousePressEvent(self, event):
        Debugger.debug('mouse press event received, point:', event.pos())

        # to catch tablet events (for some reason, it results in a mousePrEv too)
        if self.ignore_mouse_event:
            self.ignore_mouse_event = False
            return

        # there might be a proxy widget meant to receive the event instead of the flow
        QGraphicsView.mousePressEvent(self, event)

        # to catch any Proxy that received the event. Checking for event.isAccepted() or what is returned by
        # QGraphicsView.mousePressEvent(...) both didn't work so far, so I do it manually
        if self.ignore_mouse_event:
            self.ignore_mouse_event = False
            return

        if event.button() == Qt.LeftButton:
            if self.node_choice_proxy.isVisible():
                self.hide_node_choice_widget()
            else:
                if find_type_in_object(self.itemAt(event.pos()),
                                       PortInstanceGate):
                    self.gate_selected = self.itemAt(event.pos())
                    self.dragging_connection = True

            self.left_mouse_pressed_in_flow = True

        elif event.button() == Qt.RightButton:
            if len(self.items(event.pos())) == 0:
                self.node_choice_widget.reset_list()
                self.show_node_choice_widget(event.pos())

        elif event.button() == Qt.MidButton:
            self.panning = True
            self.pan_last_x = event.x()
            self.pan_last_y = event.y()
            event.accept()

        self.mouse_press_pos = self.mapToScene(event.pos())
Esempio n. 23
0
 def get_class_from_file(self, file_path, file_name, class_name):
     Debugger.debug(file_path)
     Debugger.debug(file_name)
     Debugger.debug(class_name)
     sys.path.append(file_path)
     new_module = __import__(file_name, fromlist=[class_name])
     new_class = getattr(new_module, class_name)
     return new_class
Esempio n. 24
0
    def get_val(self):
        """applies on DATA; called NI internally AND externally"""
        Debugger.debug(
            'get value in', self.direction, 'port instance',
            self.parent_node_instance.inputs.index(self) if self.direction
            == 'input' else self.parent_node_instance.outputs.index(self),
            'of', self.parent_node_instance.parent_node.title)
        Debugger.debug('my value is', self.val)

        if self.direction == 'input':
            if len(self.connected_port_instances) == 0:
                if self.widget:
                    return self.widget.get_val()
                else:
                    return None
            else:
                Debugger.debug('calling connected port for val')
                return self.connected_port_instances[0].get_val()
        elif self.direction == 'output':
            Debugger.debug('returning val directly')
            if self.parent_node_instance.gen_data_on_request:
                self.parent_node_instance.update()
            return self.val
Esempio n. 25
0
    def parse_nodes(self, j_str, package_path, package_name):
        import json

        # strict=False is necessary to allow 'control characters' like '\n' for newline when loading the json
        j_obj = json.loads(j_str, strict=False)

        Debugger.debug(j_obj['type'])
        if j_obj['type'] != 'vyScriptFP nodes package':
            return

        # package_title = j_obj['title']
        # package_description = j_obj['description']
        j_nodes_list = j_obj['nodes']

        num_nodes = len(j_nodes_list)
        for ni in range(num_nodes):  # new node
            j_node = j_nodes_list[ni]

            new_node = Node()


            node_title = j_node['title']
            node_class_name = j_node['class name']
            node_description = j_node['description']
            node_type = j_node['type']
            node_has_main_widget = j_node['has main widget']
            node_main_widget_pos = j_node['widget position'] if node_has_main_widget else None
            node_design_style = j_node['design style']
            node_color = j_node['color']

            # every node has a custom module name which differs from it's name to prevent import issues when using
            # multiple (different) Nodes with same titles
            # FOR FURTHER EXPLANATION: see node manager
            node_module_name = j_node['module name']
            module_name_separator = '___'



            #   CUSTOM CLASS IMPORTS ----------------------------------------------------------------------------
            # creating all the necessary path variables here for all potentially imported classes


            #       IMPORT NODE INSTANCE SUBCLASS
            node_instance_class_file_path = package_path+'/nodes/'+node_module_name+'/'
            node_instance_widgets_file_path = node_instance_class_file_path+'/widgets'
            node_instance_filename = node_module_name  # the NI file's name is just the 'module name'
            new_node_instance_class = self.get_class_from_file(file_path=node_instance_class_file_path,
                                                               file_name=node_instance_filename,
                                                               class_name=node_class_name+'_NodeInstance')
            self.all_node_instance_classes[new_node] = new_node_instance_class

            #       IMPORT MAIN WIDGET
            if node_has_main_widget:
                main_widget_filename = node_module_name+module_name_separator+'main_widget'
                new_node.main_widget_class = self.get_class_from_file(file_path=node_instance_widgets_file_path,
                                                                      file_name=main_widget_filename,
                                                                      class_name=node_class_name+'_NodeInstance_MainWidget')

            #       I need to create the dict for the node's potential custom input widgets already here
            self.custom_node_input_widget_classes[new_node] = {}
            for w_name in j_node['custom input widgets']:
                input_widget_filename = node_module_name+module_name_separator+w_name
                custom_widget_class = self.get_class_from_file(file_path=node_instance_widgets_file_path,
                                                               file_name=input_widget_filename,
                                                               class_name=w_name+'_PortInstanceWidget')
                self.custom_node_input_widget_classes[new_node][w_name] = custom_widget_class


            #   note: the input widget classes get imported below in the loop
            # ---------------------------------------------------------------------------------------------------


            j_n_inputs = j_node['inputs']
            inputs = []
            num_inputs = len(j_n_inputs)
            for ii in range(num_inputs):
                j_input = j_n_inputs[ii]
                i_type = j_input['type']
                i_label = j_input['label']
                i_has_widget = None
                i_widget_type = ''
                i_widget_name = ''
                i_widget_pos = None
                if i_type == 'data':
                    i_has_widget = j_input['has widget']
                    if i_has_widget:
                        i_widget_type = j_input['widget type']
                        i_widget_pos = j_input['widget position']
                        if i_widget_type == 'custom widget':
                            i_widget_name = j_input['widget name']
                new_input = NodePort()
                new_input.type_ = i_type
                new_input.label = i_label
                if i_has_widget:
                    new_input.widget_type = i_widget_type
                    new_input.widget_name = i_widget_name
                    if i_widget_pos:
                        new_input.widget_pos = i_widget_pos
                else:
                    new_input.widget_type = 'None'
                inputs.append(new_input)

            j_n_outputs = j_node['outputs']
            outputs = []
            num_outputs = len(j_n_outputs)
            for oi in range(num_outputs):
                j_output = j_n_outputs[oi]
                o_type = j_output['type']
                o_label = j_output['label']
                new_output = NodePort()
                new_output.type_ = o_type
                new_output.label = o_label
                outputs.append(new_output)

            new_node.title = node_title
            new_node.description = node_description
            new_node.type_ = node_type
            new_node.package = package_name
            new_node.has_main_widget = node_has_main_widget
            if node_has_main_widget:
                new_node.main_widget_pos = node_main_widget_pos
            new_node.design_style = node_design_style
            new_node.color = QColor(node_color)
            new_node.inputs = inputs
            new_node.outputs = outputs

            
            self.custom_nodes.append(new_node)
            self.all_nodes.append(new_node)


        Debugger.debug(len(self.custom_nodes), 'nodes imported')
Esempio n. 26
0
 def dropEvent(self, event):
     text = event.mimeData().text()
     item: QListWidgetItem = event.mimeData()
     Debugger.debug('drop received in Flow:', text)