Пример #1
0
    def __init__(self, node_block: NodeBlock):
        super().__init__(node_block.node.name, "")
        self.layout = QGridLayout()

        # Connect node
        self.node = node_block
        self.parameters = dict()
        self.edited_data = dict()
        self.has_edits = False

        # Build main_layout
        title_label = CustomLabel("Edit parameters")
        title_label.setStyleSheet(style.NODE_LABEL_STYLE)
        title_label.setAlignment(Qt.AlignCenter)
        self.layout.addWidget(title_label, 0, 0, 1, 2)

        # Input box
        in_dim_label = CustomLabel("Input")
        in_dim_label.setStyleSheet(style.IN_DIM_LABEL_STYLE)
        in_dim_label.setAlignment(Qt.AlignRight)
        self.layout.addWidget(in_dim_label, 1, 0)

        in_dim_box = CustomTextBox(','.join(map(str, node_block.in_dim)))
        in_dim_box.setValidator(ArithmeticValidator.TENSOR)

        self.layout.addWidget(in_dim_box, 1, 1)
        self.parameters["in_dim"] = in_dim_box

        if not node_block.is_head:
            in_dim_box.setReadOnly(True)

        # Display parameters if present
        counter = 2
        if node_block.node.param:
            counter = self.append_node_params(node_block.node, node_block.block_data)

        # "Apply" button which saves changes
        apply_button = CustomButton("Apply")
        apply_button.clicked.connect(self.save_data)
        self.layout.addWidget(apply_button, counter, 0)

        # "Cancel" button which closes the dialog without saving
        cancel_button = CustomButton("Cancel")
        cancel_button.clicked.connect(self.close)
        self.layout.addWidget(cancel_button, counter, 1)

        self.layout.setColumnStretch(0, 1)
        self.layout.setColumnStretch(1, 1)

        self.render_layout()
Пример #2
0
    def show_section(label: CustomLabel, buttons: dict):
        """
        This method shows the given dictionary of buttons with its label.

        Parameters
        ----------
        label: CustomLabel
        buttons: dict

        """

        label.show()
        label.setStyleSheet(style.NODE_LABEL_STYLE)
        for tool in buttons.values():
            tool.show()
Пример #3
0
    def hide_section(label: CustomLabel, buttons: dict):
        """
        This method hides the given dictionary of buttons with its label.

        Parameters
        ----------
        label: CustomLabel
        buttons: dict

        """

        label.hide()
        label.setStyleSheet(style.HIDDEN_LABEL_STYLE)
        for tool in buttons.values():
            tool.hide()
            if type(tool) is NodeButton:
                tool.setStyleSheet(style.HIDDEN_LABEL_STYLE)
Пример #4
0
    def __init__(self, node_block: NodeBlock):
        super().__init__(node_block.node.name, "")
        self.layout = QGridLayout()

        # Connect node
        self.node = node_block
        self.new_in_dim = ','.join(map(str, node_block.in_dim))
        self.in_dim_box = CustomTextBox()
        self.has_edits = False

        # Build main_layout
        title_label = CustomLabel("Edit network input")
        title_label.setStyleSheet(style.NODE_LABEL_STYLE)
        title_label.setAlignment(Qt.AlignCenter)
        self.layout.addWidget(title_label, 0, 0, 1, 2)

        # Input box
        in_dim_label = CustomLabel("Input shape")
        in_dim_label.setStyleSheet(style.IN_DIM_LABEL_STYLE)
        in_dim_label.setAlignment(Qt.AlignRight)
        self.layout.addWidget(in_dim_label, 1, 0)

        self.in_dim_box.setText(self.new_in_dim)
        self.in_dim_box.setValidator(ArithmeticValidator.TENSOR)

        self.layout.addWidget(self.in_dim_box, 1, 1)

        if not node_block.is_head:
            self.in_dim_box.setReadOnly(True)

        # "Apply" button which saves changes
        apply_button = CustomButton("Apply")
        apply_button.clicked.connect(self.save_data)
        self.layout.addWidget(apply_button, 2, 0)

        # "Cancel" button which closes the dialog without saving
        cancel_button = CustomButton("Cancel")
        cancel_button.clicked.connect(self.close)
        self.layout.addWidget(cancel_button, 2, 1)

        self.layout.setColumnStretch(0, 1)
        self.layout.setColumnStretch(1, 1)

        self.render_layout()
Пример #5
0
    def __init__(self, message: str, message_type: MessageType):
        super().__init__('', message)

        # Set the dialog stile depending on message_type
        if message_type == MessageType.MESSAGE:
            title_label = CustomLabel('Message', alignment=Qt.AlignCenter)
            title_label.setStyleSheet(style.NODE_LABEL_STYLE)
        else:
            title_label = CustomLabel('Error', alignment=Qt.AlignCenter)
            title_label.setStyleSheet(style.ERROR_LABEL_STYLE)

        # Set content label
        mess_label = CustomLabel(f"\n{self.content}\n", alignment=Qt.AlignCenter)

        # Compose widgets
        self.layout.addWidget(title_label)
        self.layout.addWidget(mess_label)

        self.render_layout()
Пример #6
0
    def init_layout(self) -> None:
        """
        This method sets up the the property block main_layout with
        the property parameters.

        """

        # Override title label
        self.title_label.setText(self.property_type)
        self.title_label.setStyleSheet(style.PROPERTY_TITLE_STYLE)
        self.condition_label.setStyleSheet(style.PROPERTY_CONDITION_STYLE)
        self.main_layout.addWidget(self.title_label)
        self.main_layout.addWidget(self.condition_label)

        self.init_grid()

        formula_label = CustomLabel("Formula")
        formula_label.setStyleSheet(style.PAR_NODE_STYLE)
        self.property_label.setStyleSheet(style.DIM_NODE_STYLE)
        self.content_layout.addWidget(formula_label, 1, 0)
        self.content_layout.addWidget(self.property_label, 1, 1)
Пример #7
0
    def __init__(self, message):
        super().__init__("", message)

        # Set title label
        title_label = CustomLabel("Input required")
        title_label.setStyleSheet(style.NODE_LABEL_STYLE)
        title_label.setAlignment(Qt.AlignCenter)

        # Set message label
        mess_label = CustomLabel("\n" + self.content + "\n")
        mess_label.setAlignment(Qt.AlignCenter)

        # Set input reading
        self.input = None
        input_line = CustomTextBox()
        input_line.setValidator(QRegExpValidator(QRegExp(
            ArithmeticValidator.TENSOR.regExp().pattern() + "|" +
            ArithmeticValidator.TENSOR_LIST.regExp().pattern())))

        # Add buttons to close the dialog
        confirm_button = CustomButton("Ok")
        confirm_button.clicked.connect(self.save_input)

        cancel_button = CustomButton("Cancel")
        cancel_button.clicked.connect(self.cancel)

        buttons = QWidget()
        buttons_layout = QHBoxLayout()
        buttons_layout.addWidget(confirm_button)
        buttons_layout.addWidget(cancel_button)
        buttons.setLayout(buttons_layout)

        # Compose widgets
        self.layout.addWidget(title_label)
        self.layout.addWidget(mess_label)
        self.layout.addWidget(input_line)
        self.layout.addWidget(buttons)

        self.render_layout()
Пример #8
0
    def __init__(self, message: str):
        super().__init__("", message)
        # Override window title
        self.setWindowTitle("Wait...")

        # Set content label
        message_label = CustomLabel(self.content)
        message_label.setStyleSheet(style.LOADING_LABEL_STYLE)

        # Set loading bar
        progress_bar = ProgressBar(self, minimum=0, maximum=0,
                                   textVisible=False, objectName="ProgressBar")
        progress_bar.setStyleSheet(style.PROGRESS_BAR_STYLE)

        # Compose widgets
        self.layout.addWidget(message_label)
        self.layout.addWidget(progress_bar)

        self.render_layout()

        # Disable the dialog frame and close button
        self.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)
        self.setWindowFlags(Qt.FramelessWindowHint)
Пример #9
0
    def __init__(self, property_block: PropertyBlock):
        super().__init__("Edit property", "")
        self.property_block = property_block
        self.new_property = self.property_block.smt_string
        self.has_edits = False
        self.layout = QGridLayout()

        # Build main_layout
        title_label = CustomLabel("SMT property")
        title_label.setStyleSheet(style.NODE_LABEL_STYLE)
        title_label.setAlignment(Qt.AlignCenter)
        self.layout.addWidget(title_label, 0, 0, 1, 2)

        # Input box
        smt_label = CustomLabel("SMT-LIB definition")
        smt_label.setStyleSheet(style.IN_DIM_LABEL_STYLE)
        smt_label.setAlignment(Qt.AlignRight)
        self.layout.addWidget(smt_label, 1, 0)

        self.smt_box = CustomTextArea()
        self.smt_box.insertPlainText(self.new_property)
        self.layout.addWidget(self.smt_box, 1, 1)

        # "Apply" button which saves changes
        apply_button = CustomButton("Apply")
        apply_button.clicked.connect(self.save_data)
        self.layout.addWidget(apply_button, 2, 0)

        # "Cancel" button which closes the dialog without saving
        cancel_button = CustomButton("Cancel")
        cancel_button.clicked.connect(self.close)
        self.layout.addWidget(cancel_button, 2, 1)

        self.layout.setColumnStretch(0, 1)
        self.layout.setColumnStretch(1, 1)

        self.render_layout()
Пример #10
0
    def append_node_params(self, node: NetworkNode, current_data: dict) -> int:
        """

        This method adds to the dialog layer the editable parameters of
        the node, and returns the last row counter for the grid main_layout.

        Attributes
        ----------
        node: NetworkNode
            The node whose parameters are displayed.
        current_data: dict
            The node current data.
        Returns
        ----------
        int
            The last row counter.

        """

        # Init column counter
        counter = 2

        # Display parameter labels
        for param, value in node.param.items():
            param_label = CustomLabel(param)
            if node.param[param]["editable"] == "false":
                param_label.setStyleSheet(style.UNEDITABLE_PARAM_LABEL_STYLE)

            param_label.setAlignment(Qt.AlignRight)
            # Set the tooltip of the input with the description
            param_label.setToolTip("<" + value["type"] + ">: "
                                   + value["description"])
            self.layout.addWidget(param_label, counter, 0)

            # Display parameter values
            if value["type"] == "boolean":
                line = CustomComboBox()
                line.addItem("True")
                line.addItem("False")
                line.setPlaceholderText(str(current_data[param]))
            else:
                line = CustomTextBox()
                if node.param[param]["editable"] == "false":
                    line.setReadOnly(True)
                if isinstance(current_data[param], Tensor) or isinstance(current_data[param], np.ndarray):
                    line.setText("(" + ','.join(map(str, current_data[param].shape)) + ")")
                elif isinstance(current_data[param], tuple):
                    line.setText(','.join(map(str, current_data[param])))
                else:
                    line.setText(str(current_data[param]))

                # Set type validator
                validator = None
                if value["type"] == "int":
                    validator = ArithmeticValidator.INT
                elif value["type"] == "float":
                    validator = ArithmeticValidator.FLOAT
                elif value["type"] == "Tensor" or value["type"] == "list of ints":
                    validator = ArithmeticValidator.TENSOR
                elif value["type"] == "list of Tensors":
                    validator = ArithmeticValidator.TENSOR_LIST
                line.setValidator(validator)

            if node.param[param]["editable"] == "false":
                line.setStyleSheet(style.UNEDITABLE_VALUE_LABEL_STYLE)
            self.layout.addWidget(line, counter, 1)

            # Keep trace of CustomTextBox objects
            self.parameters[param] = line
            counter += 1

        return counter
Пример #11
0
class BlocksToolbar(QToolBar):
    """
    This class defines a toolbar containing all the blocks available to draw a
    neural network: each type of block is read from a file in order to build a list
    of NetworkNode objects to be displayed.

    Attributes
    ----------
    NODE_FILE_PATH : str
        Path of the JSON file containing all information about the implemented
        nodes available to displaying.
    blocks : dict
        Dictionary of blocks connecting each block name with a NetworkNode.
    properties : dict
        Dictionary of properties connecting each property name with a NetworkProperty.
    f_buttons : dict
        Dictionary of buttons connecting a function name to a CustomButton.
    b_buttons : dict
        Dictionary connecting each block name to a CustomButton, which
        makes the corresponding node appear.
    p_buttons : dict
        Dictionary connecting each property name to a CustomButton, which
        makes the corresponding property appear.
    toolbar_tools_label : CustomLabel
        Label of the toolbar introducing tools.
    toolbar_blocks_label : CustomLabel
        Label of the toolbar introducing blocks types.
    toolbar_properties_label : CustomLabel
        Label of the toolbar introducing property names.
    isToolbar_tools_label_visible : bool
        Tells if the tools button are visible in the toolbar.
    isToolbar_blocks_label_visible : bool
        Tells if the blocks button are visible in the toolbar.
    isToolbar_properties_label_visible : bool
        Tells if the properties button are visible in the toolbar.

    Methods
    ----------
    __display_tools()
        This method displays on the toolbar the CustomButtons related to
        available tools.
    __init_blocks()
        This method reads from file all types of blocks storing them.
    __display_blocks()
        This method displays on the toolbar all buttons related to types of
        blocks.
    change_tools_mode()
        This method changes the visibility of the tools section of the toolbar.
    change_blocks_mode()
        This method changes the visibility of the blocks section of the toolbar.
    show_section(CustomLabel, dict)
        This method shows the given objects.
    hide_section(CustomLabel, dict)
        This method hides the given objects.

    """
    def __init__(self, node_file_path: str):
        super().__init__()
        self.NODE_FILE_PATH = node_file_path
        self.setContextMenuPolicy(Qt.PreventContextMenu)
        self.blocks = dict()
        self.properties = dict()

        # Graphic buttons
        self.f_buttons = dict()
        self.b_buttons = dict()
        self.p_buttons = dict()

        # Labels
        self.toolbar_tools_label = CustomLabel("Tools")
        self.toolbar_blocks_label = CustomLabel("Nodes")
        self.toolbar_properties_label = CustomLabel("Properties")
        self.isToolbar_tools_label_visible = True
        self.isToolbar_blocks_label_visible = True
        self.isToolbar_properties_label_visible = True

        # Setup view
        self.__display_tools()
        self.__init_blocks()
        self.__display_blocks()
        self.__init_properties()
        self.__display_properties()

        # Toolbar style
        for item in self.children():
            if type(item) is QToolButton:
                item.setStyleSheet("background-color: " + style.GREEN_2)
        self.setStyleSheet(style.TOOLBAR_STYLE)

        self.setOrientation(Qt.Vertical)
        self.setMovable(False)
        self.setFloatable(False)

    def __init_blocks(self):
        """
        Uploading blocks from a JSON file storing them in a dictionary of
        NetworkNode objects.

        """

        with open(self.NODE_FILE_PATH) as json_file:
            blocks_dict = json.loads(json_file.read())

        for k, b in blocks_dict.items():
            self.blocks[k] = NetworkNode(k, b["name"], b["input"],
                                         b["parameters"], b["output"],
                                         b["description"])
            button = NodeButton(k, self.blocks[k])
            button.setToolTip(b["description"])
            self.b_buttons[k] = button

    def __init_properties(self):
        props = ("Generic SMT", "Polyhedral")

        for k in props:
            button = PropertyButton(k)
            button.setToolTip(k)
            self.p_buttons[k] = button

    def __display_tools(self):
        """
        This method adds to the toolbar all buttons related to available tools,
        displaying them in rows in order to have a flexible main_layout in every
        position of the toolbar.

        """

        # Setting the label of the toolbar
        self.addWidget(self.toolbar_tools_label)
        self.toolbar_tools_label.setAlignment(Qt.AlignCenter)
        self.toolbar_tools_label.setStyleSheet(style.NODE_LABEL_STYLE)

        # Setting the first row with horizontal main_layout
        row_1 = QWidget()
        row_1_layout = QHBoxLayout()
        row_1_layout.setSpacing(0)
        row_1_layout.setContentsMargins(0, 0, 0, 0)
        row_1_layout.setAlignment(Qt.AlignCenter)
        row_1.setLayout(row_1_layout)

        # DrawLine mode button
        draw_line_button = CustomButton()
        draw_line_button.setIcon(QIcon(ROOT_DIR + "/res/icons/line.png"))
        draw_line_button.setFixedSize(40, 40)
        draw_line_button.setToolTip("Draw line")

        # Insert block button
        insert_block_button = CustomButton()
        insert_block_button.setIcon(QIcon(ROOT_DIR + "/res/icons/insert.png"))
        insert_block_button.setFixedSize(40, 40)
        insert_block_button.setToolTip("Insert block in edge")

        # Save in a dictionary button references and add the rows to the
        # toolbar
        row_1_layout.addWidget(draw_line_button)
        row_1_layout.addWidget(insert_block_button)
        self.f_buttons["draw_line"] = draw_line_button
        self.f_buttons["insert_block"] = insert_block_button
        self.addWidget(row_1)
        self.addSeparator()

    def __display_blocks(self):
        """
        Graphical blocks are displayed in a vertical main_layout, which is put in
        a movable toolbar of fixed size.

        """

        # Labels
        self.toolbar_blocks_label.setAlignment(Qt.AlignCenter)
        self.toolbar_blocks_label.setStyleSheet(style.NODE_LABEL_STYLE)

        # Buttons
        self.addWidget(self.toolbar_blocks_label)
        for b in self.b_buttons.values():
            self.addWidget(b)

    def __display_properties(self):
        """
        Graphical properties are displayed in a vertical main_layout, which is put in
        a movable toolbar of fixed size.

        """

        # Labels
        self.toolbar_properties_label.setAlignment(Qt.AlignCenter)
        self.toolbar_properties_label.setStyleSheet(style.NODE_LABEL_STYLE)

        # Buttons
        self.addWidget(self.toolbar_properties_label)
        for p in self.p_buttons.values():
            self.addWidget(p)

    def change_tools_mode(self):
        """
        This method handles the visibility of the tool section of the toolbar.
        If all sections are not visible, then the toolbar itself is hidden,
        while if the toolbar was hidden, it is shown with the tools section.

        """

        if not self.isToolbar_tools_label_visible:
            self.show_section(self.toolbar_tools_label, self.f_buttons)
            self.isToolbar_tools_label_visible = True

            if not self.isToolbar_blocks_label_visible:
                self.show()
        else:
            self.hide_section(self.toolbar_tools_label, self.f_buttons)
            self.isToolbar_tools_label_visible = False

            if not self.isToolbar_blocks_label_visible:
                self.hide()

    def change_blocks_mode(self):
        """
        This method handles the visibility of the blocks section of the toolbar.
        If all sections are not visible, then the toolbar itself is hidden,
        while if the toolbar was hidden, it is shown with the blocks section.

        """

        if not self.isToolbar_blocks_label_visible:
            self.show_section(self.toolbar_blocks_label, self.b_buttons)
            self.isToolbar_blocks_label_visible = True

            if not self.isToolbar_tools_label_visible:
                self.show()
        else:
            self.hide_section(self.toolbar_blocks_label, self.b_buttons)
            self.isToolbar_blocks_label_visible = False

            if not self.isToolbar_tools_label_visible:
                self.hide()

    @staticmethod
    def show_section(label: CustomLabel, buttons: dict):
        """
        This method shows the given dictionary of buttons with its label.

        Parameters
        ----------
        label: CustomLabel
        buttons: dict

        """

        label.show()
        label.setStyleSheet(style.NODE_LABEL_STYLE)
        for tool in buttons.values():
            tool.show()

    @staticmethod
    def hide_section(label: CustomLabel, buttons: dict):
        """
        This method hides the given dictionary of buttons with its label.

        Parameters
        ----------
        label: CustomLabel
        buttons: dict

        """

        label.hide()
        label.setStyleSheet(style.HIDDEN_LABEL_STYLE)
        for tool in buttons.values():
            tool.hide()
            if type(tool) is NodeButton:
                tool.setStyleSheet(style.HIDDEN_LABEL_STYLE)
Пример #12
0
class PropertyBlock(GraphicBlock):
    """
    This class represents the widget associated to a
    SMTLIB property in CoCoNet.

    Attributes
    ----------
    property_type : str
        The property type (SMT, Polyhedral...).
    smt_string : str
        The SMT-LIB expression of the property.
    property_label : CustomLabel
        The visible label of the property.
    condition_label : CustomLabel
        The POST or PRE label of the property.
    variables : list
        The list of admissible variables
        for the property.

    """

    def __init__(self, block_id: str, p_type: str):
        super().__init__(block_id)
        self.property_type = p_type
        self.pre_condition = True
        self.smt_string = ""
        if p_type == "Generic SMT":
            self.label_string = "-"
        elif p_type == "Polyhedral":
            self.label_string = "Ax - b <= 0"

        self.condition_label = CustomLabel("PRE")
        self.property_label = CustomLabel(self.label_string)
        self.variables = []
        self.init_layout()
        self.init_context_menu()

    def init_layout(self) -> None:
        """
        This method sets up the the property block main_layout with
        the property parameters.

        """

        # Override title label
        self.title_label.setText(self.property_type)
        self.title_label.setStyleSheet(style.PROPERTY_TITLE_STYLE)
        self.condition_label.setStyleSheet(style.PROPERTY_CONDITION_STYLE)
        self.main_layout.addWidget(self.title_label)
        self.main_layout.addWidget(self.condition_label)

        self.init_grid()

        formula_label = CustomLabel("Formula")
        formula_label.setStyleSheet(style.PAR_NODE_STYLE)
        self.property_label.setStyleSheet(style.DIM_NODE_STYLE)
        self.content_layout.addWidget(formula_label, 1, 0)
        self.content_layout.addWidget(self.property_label, 1, 1)

    def init_context_menu(self):
        """
        This method sets up the context menu actions that
        are available for the block.

        """

        block_actions = dict()
        block_actions["Define"] = QAction("Define...", self)
        self.set_context_menu(block_actions)

    def set_label(self):
        self.property_label.setText(self.label_string)

    def set_smt_label(self):
        self.property_label.setText(self.smt_string)

    def update_condition_label(self):
        if self.pre_condition:
            self.condition_label.setText("PRE")
        else:
            self.condition_label.setText("POST")
Пример #13
0
class BlockInspector(QWidget):
    """
    This class contains the widget for displaying the description of a network
    block in the ParamToolbar. Each block attribute is labeled and wrapped
    in a drop-down box.

    Attributes
    ----------
    layout : QVBoxLayout
        Vertical main_layout of the widget.
    title_label : CustomLabel
        Title of the widget.
    description_label : CustomLabel
        Description of the block.
    parameters : QWidget
        Container of parameters.
    parameters_label : CustomLabel
        Label of parameters.
    parameters_layout : QVBoxLayout
        Vertical main_layout of parameters.
    inputs : QWidget
        Container of inputs.
    inputs_label : CustomLabel
        Label of inputs.
    inputs_layout : QVBoxLayout
        Vertical main_layout of inputs.
    outputs : QWidget
        Container of outputs.
    outputs_label : CustomLabel
        Label of outputs.
    outputs_layout : QVBoxLayout
        Vertical main_layout of outputs.

    """
    def __init__(self, block: NodeBlock):
        super().__init__()
        self.setStyleSheet(style.BLOCK_BOX_STYLE)
        self.layout = QVBoxLayout()
        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0, 0, 10, 0)
        self.setLayout(self.layout)
        self.adjustSize()
        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)

        # Widget title
        self.title_label = CustomLabel()
        self.title_label.setStyleSheet(style.TITLE_LABEL_STYLE)
        self.title_label.setText(block.block_id + ":" + block.node.name)

        # NodeBlock description
        self.description_label = CustomLabel()
        self.description_label.setStyleSheet(style.DESCRIPTION_STYLE)
        self.description_label.setWordWrap(True)
        self.description_label.setAlignment(Qt.AlignLeft)
        self.description_label.setText(block.node.descr)
        self.description_label.setSizePolicy(QSizePolicy.Preferred,
                                             QSizePolicy.Minimum)

        # Parameters section
        if block.node.param:
            self.parameters_label = CustomLabel("Parameters")
            self.parameters_label.setStyleSheet(style.NODE_LABEL_STYLE)
            self.parameters = QWidget()
            self.parameters_layout = QVBoxLayout()
            self.parameters_layout.setSpacing(0)
            self.parameters.setLayout(self.parameters_layout)
            self.parameters.setStyleSheet("padding: 0px")

            for par, values in block.node.param.items():
                self.parameters_layout.addWidget(DropDownLabel(par, values))

        # Inputs section
        if block.node.input:
            self.inputs_label = CustomLabel("Input")
            self.inputs_label.setStyleSheet(style.NODE_LABEL_STYLE)
            self.inputs = QWidget()
            self.inputs_layout = QVBoxLayout()
            self.inputs_layout.setSpacing(0)
            self.inputs.setLayout(self.inputs_layout)
            self.inputs.setStyleSheet("padding: 0px")

            for par, values in block.node.input.items():
                self.inputs_layout.addWidget(DropDownLabel(par, values))

        # Outputs section
        if block.node.output:
            self.outputs_label = CustomLabel("Output")
            self.outputs_label.setStyleSheet(style.NODE_LABEL_STYLE)
            self.outputs = QWidget()
            self.outputs_layout = QVBoxLayout()
            self.outputs_layout.setSpacing(0)
            self.outputs.setLayout(self.outputs_layout)
            self.outputs.setStyleSheet("padding: 0px")

            for par, values in block.node.output.items():
                self.outputs_layout.addWidget(DropDownLabel(par, values))

        # Compose widget
        self.layout.addWidget(self.title_label)
        self.layout.addWidget(self.description_label)

        if block.node.param:
            self.layout.addWidget(self.parameters_label)
            self.layout.addWidget(self.parameters)

        if block.node.input:
            self.layout.addWidget(self.inputs_label)
            self.layout.addWidget(self.inputs)

        if block.node.output:
            self.layout.addWidget(self.outputs_label)
            self.layout.addWidget(self.outputs)
Пример #14
0
class MainWindow(QtWidgets.QMainWindow):
    """
    This class is the main window of the program, containing all the graphics
    objects such as the toolbar, the state bar, the menu and the canvas scene.

    Attributes
    ----------
    SYSNAME : str
        The application name displayed in the window.
    nav_menu_bar : QMenuBar
        Menu bar of the window, containing different menus.
    status_bar : QStatusBar
        Status bar of the window.
    toolbar : BlocksToolbar
        Toolbar appearing on the left of the window, showing several buttons to
        add elements to the canvas.
    parameters : ParamToolbar
        Fixed toolbar on the right of the window, displaying details about a
        certain block.
    canvas : Canvas
        Central view of the window, containing a blank space in which the
        blocks appear.

    Methods
    ----------
    connect_events()
        Connects to all signals of the elements.
    init_menu_bar()
        Sets all menus of the menu bar and their actions.
    update_status()
        Changes the status bar displaying on it the canvas mode and the
        selected items.
    change_draw_mode(DrawingMode)
        Changes the drawing mode of the canvas.
    create_from(NodeButton)
        Draws in the canvas the block corresponding to the button pressed.
    reset()
        Clears both graphical and logical network.
    open()
        Procedure to open an existing network.
    save(bool)
        Saves the current network in a new file or in the opened one.

    """

    def __init__(self):
        super(MainWindow, self).__init__()

        # Init window appearance
        self.SYSNAME = "NeVer 2"
        self.setWindowTitle(self.SYSNAME)
        self.setWindowIcon(QtGui.QIcon(ROOT_DIR + '/res/icons/logo.png'))
        self.setStyleSheet("background-color: " + style.GREY_1)

        # Navigation menu
        self.nav_menu_bar = self.menuBar()
        self.init_nav_menu_bar()

        # Blocks toolbar
        self.toolbar = BlocksToolbar(ROOT_DIR + '/res/json/blocks.json')

        # Parameters toolbar
        self.parameters = ParamToolbar()

        # Drawing Canvas
        self.canvas = Canvas(self.toolbar.blocks)

        # Status bar
        self.status_bar = QStatusBar()
        self.status_bar.setSizeGripEnabled(False)
        self.setStatusBar(self.status_bar)
        self.status_bar.setStyleSheet(style.STATUS_BAR_STYLE)
        self.status_bar_mode_label = CustomLabel()
        self.status_bar_mode_label.setStyleSheet(style.STATUS_BAR_WIDGET_STYLE)
        self.status_bar_selections_label = CustomLabel()
        self.status_bar_selections_label.setStyleSheet(style.STATUS_BAR_WIDGET_STYLE)
        self.status_bar.addPermanentWidget(self.status_bar_selections_label)
        self.status_bar.addPermanentWidget(self.status_bar_mode_label)

        # And adding them to the window
        self.addDockWidget(Qt.RightDockWidgetArea, self.parameters, Qt.Vertical)
        self.addToolBar(QtCore.Qt.ToolBarArea.LeftToolBarArea, self.toolbar)
        self.setCentralWidget(self.canvas.view)

        self.connect_events()

    def connect_events(self):
        """
        Associate the various events coming from button signals and other
        graphical objects to the correct actions.

        """

        # Block buttons
        for b in itertools.chain(self.toolbar.b_buttons.values(),
                                 self.toolbar.p_buttons.values()):
            b.clicked.connect(self.create_from(b))

        # Draw line button
        self.toolbar.f_buttons["draw_line"].clicked \
            .connect(lambda: self.change_draw_mode(DrawingMode.DRAW_LINE))

        # Insert block button
        self.toolbar.f_buttons["insert_block"].clicked \
            .connect(lambda: self.change_draw_mode(DrawingMode.DRAW_BLOCK))

        # Parameters box appearing
        self.canvas.param_requested \
            .connect(lambda: self.parameters.display(self.canvas.block_to_show))

        # State bar updating
        self.canvas.scene.has_changed_mode \
            .connect(lambda: self.update_status())
        self.canvas.scene.selectionChanged \
            .connect(lambda: self.update_status())

    def init_nav_menu_bar(self):
        """
        This method creates the navigation bar by adding the menus and
        corresponding actions.

        """

        self.nav_menu_bar.setStyleSheet(style.MENU_BAR_STYLE)
        self.setContextMenuPolicy(Qt.PreventContextMenu)
        actions_dict = dict()

        with open(ROOT_DIR + '/res/json/menu.json') as json_menu:
            menu = json.loads(json_menu.read())

        for menu_item, actions in menu.items():
            entry = self.nav_menu_bar.addMenu(menu_item)
            entry.setStyleSheet(style.MENU_BAR_STYLE)

            for a, v in actions.items():
                action_item = QAction(a, self)
                if "Shortcut" in v.keys():
                    action_item.setShortcut(v["Shortcut"])
                if v["checkable"] == "True":
                    action_item.setCheckable(True)
                    action_item.setChecked(True)
                entry.addAction(action_item)
                actions_dict[f"{menu_item}:{a}"] = action_item

        # Triggers connection
        actions_dict["File:New..."].triggered.connect(lambda: self.reset())
        actions_dict["File:Open..."].triggered.connect(lambda: self.open())
        actions_dict["File:Load property..."].triggered.connect(lambda: self.canvas.project.open_property())
        actions_dict["File:Save"].triggered.connect(lambda: self.save(False))
        actions_dict["File:Save as..."].triggered.connect(lambda: self.save())
        actions_dict["File:Exit"].triggered.connect(lambda: self.close())

        actions_dict["Edit:Copy"].triggered.connect(lambda: self.canvas.copy_selected())
        actions_dict["Edit:Paste"].triggered.connect(lambda: self.canvas.paste_selected())
        actions_dict["Edit:Cut"].triggered.connect(lambda: self.canvas.cut_selected())
        actions_dict["Edit:Delete"].triggered.connect(lambda: self.canvas.delete_selected())
        actions_dict["Edit:Clear canvas"].triggered.connect(lambda: self.clear())
        actions_dict["Edit:Draw connection"].triggered.connect(lambda: self.change_draw_mode(DrawingMode.DRAW_LINE))
        actions_dict["Edit:Edit node"].triggered.connect(
            lambda: self.canvas.scene.edit_node(self.edit_action_validation()))

        actions_dict["View:Zoom in"].triggered.connect(lambda: self.canvas.zoom_in())
        actions_dict["View:Zoom out"].triggered.connect(lambda: self.canvas.zoom_out())
        actions_dict["View:Dimensions"].toggled.connect(lambda: self.canvas.scene.switch_dim_visibility())
        actions_dict["View:Tools"].toggled.connect(lambda: self.toolbar.change_tools_mode())
        actions_dict["View:Blocks"].toggled.connect(lambda: self.toolbar.change_blocks_mode())
        actions_dict["View:Parameters"].triggered.connect(
            lambda: self.canvas.show_parameters(self.parameters_action_validation()))

        actions_dict["Learning:Train..."].triggered.connect(lambda: self.canvas.train_network())
        actions_dict["Learning:Prune..."].triggered.connect(lambda: self.temp_window())

        actions_dict["Verification:Verify..."].triggered.connect(lambda: self.canvas.verify_network())
        actions_dict["Verification:Repair..."].triggered.connect(lambda: self.temp_window())

        actions_dict["Help:Show guide"].triggered.connect(lambda: self.show_help())

    @staticmethod
    def temp_window():
        dialog = MessageDialog("Work in progress...", MessageType.MESSAGE)
        dialog.exec()

    def create_from(self, button: QPushButton):
        """
        This method draws on the canvas the block corresponding to the pressed
        BlockButton.

        Parameters
        ----------
        button : CustomButton
            The pressed button.

        """

        def pressed():
            if isinstance(button, NodeButton):
                self.canvas.draw_node(button.node_type)
            elif isinstance(button, PropertyButton):
                if self.canvas.project.network.nodes:
                    self.canvas.draw_property(button.name)

        return pressed

    def update_status(self):
        """
        This method updates the widget in the status bar, displaying the
        items selected and the current drawing mode.

        """

        # Show the canvas drawing mode
        if self.canvas.scene.mode == DrawingMode.DRAW_LINE:
            self.status_bar_mode_label.setText("GraphicLine drawing")
        elif self.canvas.scene.mode == DrawingMode.DRAW_BLOCK:
            self.status_bar_mode_label.setText("Block insertion")
        else:
            self.status_bar_mode_label.setText("")

        # Show the selected items, if any
        if not self.canvas.scene.selectedItems():
            self.status_bar_selections_label.setText("")
        else:
            selections = ""
            semicolons = ["; " for _ in range(len(self.canvas.scene.selectedItems()))]
            semicolons[-1] = ""  # No semicolon for the last element in the selections list

            for counter, item in enumerate(self.canvas.scene.selectedItems()):
                if type(item) is QGraphicsRectItem:
                    # If the item is a rect, prev_node_id is written
                    selections += self.canvas.scene.blocks[item].block_id
                    selections += semicolons[counter]
                elif type(item) is GraphicLine:
                    # If the item is a line, origin and destination ids are written
                    origin = self.canvas.scene.blocks[item.origin].block_id
                    destination = self.canvas.scene.blocks[item.destination].block_id
                    selections += origin + "->" + destination
                    selections += semicolons[counter]

            self.status_bar_selections_label.setText(selections)

    def change_draw_mode(self, newmode: DrawingMode = None):
        """
        This method changes the drawing mode of the canvas when the user
        clicks on the corresponding button. The mode changes depending
        on the previous one.

        Parameters
        ----------
        newmode : DrawingMode, optional
            Specifies the new DrawingMode to use. (Default: None)

        """

        if newmode is None:
            self.canvas.scene.set_mode(DrawingMode.IDLE)
        else:
            curmode = self.canvas.scene.mode
            if newmode == curmode:
                self.canvas.scene.set_mode(DrawingMode.IDLE)
            else:
                self.canvas.scene.set_mode(newmode)

    def clear(self):
        """
        Utility for deleting the content of the window. Before taking effect,
        it prompts the user to confirm.

        """

        if self.canvas.num_nodes > 0:
            alert_dialog = ConfirmDialog("Clear workspace",
                                         "The network will be erased and your work will be lost.\n"
                                         "Do you wish to continue?")
            alert_dialog.exec()
            if alert_dialog.confirm:
                self.canvas.clear_scene()
                self.canvas.scene.has_changed_mode.connect(lambda: self.update_status())
                self.canvas.scene.selectionChanged.connect(lambda: self.update_status())
                self.update_status()
                self.setWindowTitle(self.SYSNAME)
        else:
            self.canvas.clear_scene()
            self.canvas.scene.has_changed_mode.connect(lambda: self.update_status())
            self.canvas.scene.selectionChanged.connect(lambda: self.update_status())
            self.update_status()
            self.setWindowTitle(self.SYSNAME)

    def reset(self):
        """
        This method clears the scene and the network, stops to work on the file
        and restarts from scratch.

        """

        self.clear()
        self.canvas.project.file_name = ("", "")
        self.setWindowTitle(self.SYSNAME)

    def open(self):
        """
        This method handles the opening of a file.

        """

        if self.canvas.renderer.disconnected_network:
            # If there is already a network in the canvas, it is asked to the
            # user if continuing with opening.
            confirm_dialog = ConfirmDialog("Open network",
                                           "A new network will be opened "
                                           "cancelling the current nodes.\n"
                                           "Do you wish to continue?")
            confirm_dialog.exec()
            # If the user clicks on "yes", the canvas is cleaned, a net is
            # opened and the window title is updated.
            if confirm_dialog is not None:
                if confirm_dialog.confirm:
                    # The canvas is cleaned
                    self.canvas.clear_scene()
                    self.canvas.scene.has_changed_mode.connect(lambda: self.update_status())
                    self.canvas.scene.selectionChanged.connect(lambda: self.update_status())
                    self.update_status()
                    # A file is opened
                    self.canvas.project.open()
                    if self.canvas.project.network is not None:
                        self.setWindowTitle(self.SYSNAME + " - " + self.canvas.project.network.identifier)
        else:
            # If the canvas was already empty, the opening function is directly
            # called
            self.canvas.project.open()
            if self.canvas.project.network is not None:
                self.setWindowTitle(self.SYSNAME + " - " + self.canvas.project.network.identifier)

    def save(self, _as: bool = True):
        """
        This method saves the current network if the format is correct

        Parameters
        ----------
        _as : bool, optional
            This attribute distinguishes between "save" and "save as".
            If _as is True the network will be saved in a new file, while
            if _as is False the network will overwrite the current one.
            (Default: True)

        """

        if len(self.canvas.renderer.NN.nodes) == 0 or \
                len(self.canvas.renderer.NN.edges) == 0:
            # Limit case: one disconnected node -> new network with one node
            if len(self.canvas.renderer.disconnected_network) == 1:
                for node in self.canvas.renderer.disconnected_network:
                    try:
                        self.canvas.renderer.add_node_to_nn(node)
                        self.canvas.project.save(_as)
                        self.setWindowTitle(self.SYSNAME + " - " + self.canvas.project.network.identifier)
                    except Exception as e:
                        error_dialog = MessageDialog(str(e), MessageType.ERROR)
                        error_dialog.exec()

            # More than one disconnected nodes cannot be saved
            elif len(self.canvas.renderer.disconnected_network) > 1:
                not_sequential_dialog = MessageDialog("The network is not sequential, and "
                                                      "cannot be saved.",
                                                      MessageType.ERROR)
                not_sequential_dialog.exec()
            else:
                # Network is empty
                message = MessageDialog("The network is empty!", MessageType.MESSAGE)
                message.exec()

        elif self.canvas.renderer.is_nn_sequential():
            # If there are logical nodes, the network is sequential
            every_node_connected = True
            # every node has to be in the nodes dictionary
            for node in self.canvas.renderer.disconnected_network:
                if node not in self.canvas.project.network.nodes:
                    every_node_connected = False
                    break

            if every_node_connected:
                self.canvas.project.save(_as)
                if self.canvas.project.network is not None:
                    self.setWindowTitle(self.SYSNAME + " - " + self.canvas.project.network.identifier)
            else:
                # If there are disconnected nodes, a message is displayed to the
                # user to choose if saving only the connected network
                confirm_dialog = ConfirmDialog("Save network",
                                               "All the nodes outside the "
                                               "sequential network will lost.\n"
                                               "Do you wish to continue?")
                confirm_dialog.exec()
                if confirm_dialog.confirm:
                    self.canvas.project.save(_as)
                    if self.canvas.project.network is not None:
                        self.setWindowTitle(self.SYSNAME + " - " + self.canvas.project.network.identifier)
        else:
            # If the network is not sequential, it cannot be saved.
            not_sequential_dialog = MessageDialog("The network is not sequential and "
                                                  "cannot be saved.",
                                                  MessageType.ERROR)
            not_sequential_dialog.exec()

    def edit_action_validation(self) -> Optional[NodeBlock]:
        """
        This method performs a check on the object on which the edit
        action is called, in order to prevent unwanted operations.

        Returns
        ----------
        NodeBlock
            The graphic wrapper of the NetworkNode selected, if present.

        """

        if self.canvas.scene.selectedItems():
            if type(self.canvas.scene.selectedItems()[0]) is QGraphicsRectItem:
                # Return block graphic object
                return self.canvas.scene.blocks[self.canvas.scene.selectedItems()[0]]
            elif type(self.canvas.scene.selectedItems()[0]) is GraphicLine:
                msg_dialog = MessageDialog("Can't edit edges, please select a block instead.",
                                           MessageType.ERROR)
                msg_dialog.exec()
        else:
            err_dialog = MessageDialog("No block selected.", MessageType.MESSAGE)
            err_dialog.exec()

    def parameters_action_validation(self) -> Optional[NodeBlock]:
        """
        This method performs a check on the object on which the parameters
        action is called, in order to prevent unwanted operations.

        Returns
        ----------
        NodeBlock
            The graphic wrapper of the NetworkNode selected, if present.

        """

        if self.canvas.scene.selectedItems():
            if type(self.canvas.scene.selectedItems()[0]) is QGraphicsRectItem:
                # Return block graphic object
                return self.canvas.scene.blocks[self.canvas.scene.selectedItems()[0]]
            elif type(self.canvas.scene.selectedItems()[0]) is GraphicLine:
                msg_dialog = MessageDialog("No parameters available for connections.", MessageType.ERROR)
                msg_dialog.exec()
        else:
            err_dialog = MessageDialog("No block selected.", MessageType.MESSAGE)
            err_dialog.exec()

    @staticmethod
    def show_help():
        help_dialog = HelpDialog()
        help_dialog.exec()
Пример #15
0
    def __init__(self, property_block: PropertyBlock):
        super().__init__("Edit property", "")
        self.property_block = property_block
        self.has_edits = False
        self.property_list = []
        self.viewer = CustomTextArea()
        self.viewer.setReadOnly(True)
        self.viewer.setFixedHeight(100)
        grid = QGridLayout()

        # Build main_layout
        title_label = CustomLabel("Polyhedral property")
        title_label.setStyleSheet(style.NODE_LABEL_STYLE)
        title_label.setAlignment(Qt.AlignCenter)
        grid.addWidget(title_label, 0, 0, 1, 3)

        # Labels
        var_label = CustomLabel("Variable")
        var_label.setStyleSheet(style.IN_DIM_LABEL_STYLE)
        var_label.setAlignment(Qt.AlignRight)
        grid.addWidget(var_label, 1, 0)

        relop_label = CustomLabel("Operator")
        relop_label.setStyleSheet(style.IN_DIM_LABEL_STYLE)
        relop_label.setAlignment(Qt.AlignCenter)
        grid.addWidget(relop_label, 1, 1)

        value_label = CustomLabel("Value")
        value_label.setStyleSheet(style.IN_DIM_LABEL_STYLE)
        value_label.setAlignment(Qt.AlignLeft)
        grid.addWidget(value_label, 1, 2)

        self.var_cb = CustomComboBox()
        for v in property_block.variables:
            self.var_cb.addItem(v)
        grid.addWidget(self.var_cb, 2, 0)

        self.op_cb = CustomComboBox()
        operators = ["<=", "<", ">", ">="]
        for o in operators:
            self.op_cb.addItem(o)
        grid.addWidget(self.op_cb, 2, 1)

        self.val = CustomTextBox()
        self.val.setValidator(ArithmeticValidator.FLOAT)
        grid.addWidget(self.val, 2, 2)

        # "Add" button which adds the constraint
        add_button = CustomButton("Add")
        add_button.clicked.connect(
            lambda: self.add_entry(str(self.var_cb.currentText()), str(self.op_cb.currentText()), self.val.text()))
        grid.addWidget(add_button, 3, 0)

        # "Save" button which saves the state
        save_button = CustomButton("Save")
        save_button.clicked.connect(self.save_property)
        grid.addWidget(save_button, 3, 1)

        # "Cancel" button which closes the dialog without saving
        cancel_button = CustomButton("Cancel")
        cancel_button.clicked.connect(self.close)
        grid.addWidget(cancel_button, 3, 2)

        grid.setColumnStretch(0, 1)
        grid.setColumnStretch(1, 1)
        grid.setColumnStretch(2, 1)

        self.layout.addLayout(grid)
        self.layout.addWidget(self.viewer, 3)
        self.render_layout()
Пример #16
0
    def __init__(self, nn: NeuralNetwork):
        super().__init__("Train Network")

        # Training elements
        self.nn = nn
        self.is_nn_trained = False
        self.dataset_path = ""
        self.dataset_params = dict()
        self.dataset_transform = tr.Compose([])
        self.params = utility.read_json(ROOT_DIR + '/res/json/training.json')
        self.gui_params = dict()
        self.loss_f = ''
        self.metric = ''
        self.grid_layout = QGridLayout()

        # Dataset
        dt_label = CustomLabel("Dataset")
        dt_label.setAlignment(Qt.AlignCenter)
        dt_label.setStyleSheet(style.NODE_LABEL_STYLE)
        self.layout.addWidget(dt_label)

        dataset_layout = QHBoxLayout()
        self.widgets["dataset"] = CustomComboBox()
        self.widgets["dataset"].addItems(
            ["MNIST", "Fashion MNIST", "Custom data source..."])
        self.widgets["dataset"].setCurrentIndex(-1)
        self.widgets["dataset"].activated \
            .connect(lambda: self.setup_dataset(self.widgets["dataset"].currentText()))
        dataset_layout.addWidget(CustomLabel("Dataset"))
        dataset_layout.addWidget(self.widgets["dataset"])
        self.layout.addLayout(dataset_layout)

        transform_layout = QHBoxLayout()
        self.widgets["transform"] = CustomComboBox()
        self.widgets["transform"].addItems([
            "No transform", "Convolutional MNIST", "Fully Connected MNIST",
            "Custom..."
        ])
        self.widgets["transform"].activated \
            .connect(lambda: self.setup_transform(self.widgets["transform"].currentText()))
        transform_layout.addWidget(CustomLabel("Dataset transform"))
        transform_layout.addWidget(self.widgets["transform"])
        self.layout.addLayout(transform_layout)

        # Separator
        sep_label = CustomLabel("Training parameters")
        sep_label.setAlignment(Qt.AlignCenter)
        sep_label.setStyleSheet(style.NODE_LABEL_STYLE)
        self.layout.addWidget(sep_label)

        # Main body
        # Activation functions for dynamic widgets
        def activation_combo(key: str):
            return lambda: self.update_grid_view(
                f"{key}:{self.widgets[key].currentText()}")

        def activation_line(key: str):
            return lambda: self.update_dict_value(key, "", self.widgets[key].
                                                  text())

        body_layout = self.create_widget_layout(self.params, activation_combo,
                                                activation_line)
        body_layout.addLayout(self.grid_layout)
        self.grid_layout.setAlignment(Qt.AlignTop)
        self.layout.addLayout(body_layout)

        # Buttons
        btn_layout = QHBoxLayout()
        self.train_btn = CustomButton("Train network")
        self.train_btn.clicked.connect(self.train_network)
        self.cancel_btn = CustomButton("Cancel")
        self.cancel_btn.clicked.connect(self.close)
        btn_layout.addWidget(self.train_btn)
        btn_layout.addWidget(self.cancel_btn)
        self.layout.addLayout(btn_layout)

        self.render_layout()
Пример #17
0
class DropDownLabel(QWidget):
    """
    This widget displays a generic parameter name and value.
    It features a drop-down arrow button that shows or hides
    the description.

    Attributes
    ----------
    layout : QVBoxLayout
        Vertical main_layout of the widget.
    top : QWidget
        First part of the widget with name, type and default value of the
        parameter.
    top_layout : QHBoxLayout
        Horizontal main_layout of the top of the widget.
    name_label : CustomLabel
        Id and type of the object.
    type_label : CustomLabel
        Object type.
    default_label : CustomLabel
        Eventual default value.
    down_button : CustomButton
        Arrow button to show/hide the description of the parameter.
    description : CustomLabel
        Description of the parameter.

    Methods
    ----------
    change_description_mode()
        This method shows or hides the description of the parameter.

    """
    def __init__(self, name: str, parameters: dict):
        super().__init__()
        self.layout = QVBoxLayout()
        self.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.layout)
        self.setStyleSheet(style.DROPDOWN_STYLE)
        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)

        # Top bar with short info
        self.top = QWidget()
        self.top.setContentsMargins(0, 0, 0, 0)
        self.top.setStyleSheet(style.DROPDOWN_TOP_STYLE)
        self.top_layout = QHBoxLayout()
        self.top_layout.setContentsMargins(0, 0, 0, 0)
        self.top.setLayout(self.top_layout)

        self.name_label = CustomLabel(name)
        self.name_label.setAlignment(Qt.AlignLeft)
        self.name_label.setStyleSheet(style.DROPDOWN_NAME_STYLE)
        self.top_layout.addWidget(self.name_label, Qt.AlignLeft)

        self.type_label = CustomLabel(parameters["type"])
        self.type_label.setAlignment(Qt.AlignLeft)
        self.type_label.setToolTip("Type")
        self.type_label.setStyleSheet(style.DROPDOWN_TYPE_STYLE)
        self.top_layout.addWidget(self.type_label, Qt.AlignLeft)

        if "default" in parameters:
            self.default_label = CustomLabel(parameters["default"])
            self.default_label.setStyleSheet(style.DROPDOWN_DEFAULT_STYLE)
            self.default_label.setToolTip("Default value")
            self.default_label.setAlignment(Qt.AlignCenter)
            self.top_layout.addWidget(self.default_label, Qt.AlignRight)

        self.down_button = CustomButton("\u25bc")
        self.down_button.setStyleSheet(style.DROPDOWN_ARROW_STYLE)
        self.down_button.clicked.connect(lambda: self.__toggle_visibility())
        self.top_layout.addWidget(self.down_button, Qt.AlignRight)

        self.layout.addWidget(self.top)

        self.description = CustomLabel(parameters["description"])
        self.description.setSizePolicy(QSizePolicy.Minimum,
                                       QSizePolicy.Maximum)
        self.description.setWordWrap(True)
        self.description.setStyleSheet(style.DESCRIPTION_STYLE)
        self.description.hide()
        self.layout.addWidget(self.description)

    def __toggle_visibility(self):
        """
        This method toggles the visibility of the parameter description
        changing the arrow icon of the button.

        """

        if self.description.isHidden():
            self.description.show()
            self.down_button.setText("\u25b2")
        else:
            self.description.hide()
            self.down_button.setText("\u25bc")