Ejemplo n.º 1
0
class ConstituentNodeEditEmbed(UIEmbed):
    """ Node edit embed creates editable elements based on templates provided by Node subclass.
    It allows easy UI generation for user-customized syntactic elements or Kataja Nodes.

    :param parent: QWidget where this editor lives, QGraphicsView of some sort
    :param ui_manager: UIManager instance that manages this editor
    :param ui_key: unique, but predictable key for accessing this editor
    :param node: node that is to be associated with this editor
    """
    can_fade = False  # fade and textareas don't work well together

    def __init__(self, parent, node):
        nname = node.display_name[0].lower()
        UIEmbed.__init__(self, parent, node, 'Edit ' + nname)
        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(self.top_row_layout)
        layout.addSpacing(4)
        ui_p = self._palette
        self.setPalette(ui_p)
        ui_s = QtGui.QPalette(ui_p)
        ui_s.setColor(QtGui.QPalette.Text, ctrl.cm.secondary())
        smaller_font = qt_prefs.get_font(g.MAIN_FONT)
        big_font = QtGui.QFont(smaller_font)
        big_font.setPointSize(big_font.pointSize() * 2)
        self.view_buttons = QtWidgets.QButtonGroup(self)
        self.view_buttons.setExclusive(True)

        self.synframebutton = EyeButton(
            'synlabels', 'All nodes show their syntactic labels')
        self.synframebutton.setChecked(True)
        self.ui_manager.connect_element_to_action(self.synframebutton,
                                                  'set_synlabels_visible')
        self.view_buttons.addButton(self.synframebutton)
        hlayout = QtWidgets.QHBoxLayout()
        hlayout.addWidget(self.synframebutton)
        vlayout = QtWidgets.QVBoxLayout()
        hlayout.addLayout(vlayout)
        tt = 'Label used in syntactic computations, plain string. Visible in <i>syntactic mode</i> ' \
             'or if <i>Displayed label</i> is empty.'
        title = 'Syntactic label'
        self.synlabel = EmbeddedLineEdit(self,
                                         tip=tt,
                                         font=big_font,
                                         prefill='label',
                                         on_edit=self.synlabel_edited,
                                         on_finish=self.synlabel_finished,
                                         on_return=self.synlabel_finished)
        make_label(title, self, vlayout, tt, self.synlabel, ui_s)
        self.synlabel.setPalette(ui_p)
        vlayout.addWidget(self.synlabel)
        layout.addLayout(hlayout)

        self.nodeframebutton = EyeButton(
            'nodelabels', 'All nodes show their user-given labels')
        self.view_buttons.addButton(self.nodeframebutton)
        self.ui_manager.connect_element_to_action(self.nodeframebutton,
                                                  'set_node_labels_visible')
        tt = "Freeform label or text for node, has no effect for syntactic computation"
        title = 'User label'
        self.label = ExpandingTextArea(self,
                                       tip=tt,
                                       font=smaller_font,
                                       prefill='label',
                                       on_edit=self.label_edited,
                                       label=title,
                                       on_focus_out=self.label_finished)
        self.label.setPalette(ui_p)
        self.resize_target = self.label
        hlayout = QtWidgets.QHBoxLayout()
        hlayout.addWidget(self.nodeframebutton)
        hlayout.addWidget(self.label)
        layout.addLayout(hlayout)

        self.autoframebutton = EyeButton(
            'autolabels', 'All nodes show their autogenerated x-bar '
            'labels')
        self.ui_manager.connect_element_to_action(self.autoframebutton,
                                                  'set_autolabels_visible')
        self.view_buttons.addButton(self.autoframebutton)
        hlayout = QtWidgets.QHBoxLayout()
        hlayout.addWidget(self.autoframebutton)
        vlayout = QtWidgets.QVBoxLayout()
        hlayout.addLayout(vlayout)
        tt = "These are either XBar or Bare phrase structure labels that are updated " \
             "automatically based on projections."
        title = 'Generated label'
        self.autolabel = EmbeddedLineEdit(self,
                                          tip=tt,
                                          font=big_font,
                                          prefill='autolabel')
        self.autolabel.setReadOnly(True)
        make_label(title, self, vlayout, tt, self.autolabel)
        vlayout.addWidget(self.autolabel)

        vlayout = QtWidgets.QVBoxLayout()
        tt = 'Optional index for announcing link between multiple instances.'
        title = 'Index'
        self.index = EmbeddedLineEdit(self,
                                      tip=tt,
                                      font=big_font,
                                      prefill='i',
                                      on_finish=self.index_finished)
        self.index.setPalette(ui_p)
        self.index.setMaximumWidth(20)
        make_label(title, self, vlayout, tt, self.index)
        vlayout.addWidget(self.index)
        hlayout.addLayout(vlayout)
        layout.addLayout(hlayout)

        hlayout = QtWidgets.QHBoxLayout()
        hlayout.addSpacing(28)
        tt = 'Node can be projection from either or both of its children if those children are ' \
             'heads or projections from their children.'
        title = 'Projects from'
        self.projections = ProjectionButtons(self)
        self.projections.setMaximumWidth(200)

        vlayout = QtWidgets.QVBoxLayout()
        if not self.projections.empty:
            make_label(title, self, vlayout, tt)
        vlayout.addWidget(self.projections)
        hlayout.addLayout(vlayout)
        layout.addLayout(hlayout)
        self.ui_manager.connect_element_to_action(
            self.projections,
            'set_projection_at_embed_ui',
            connect_slot=self.projections.connect_slot)
        if self.resize_target:
            self.resize_handle = ResizeHandle(self, self.resize_target)
            layout.addWidget(self.resize_handle, 0, QtCore.Qt.AlignRight)
        self.setLayout(layout)
        self.update_embed()
        self.update_position()
        self.hide()

    def margin_x(self):
        """ Try to keep all of the host node visible, not covered by this editor.
        :return:
        """
        return (self.host.boundingRect().width() / 2) + 12

    def margin_y(self):
        """ Try to keep all of the host node visible, not covered by this editor.
        :return:
        """
        return self.host.boundingRect().height() / 2

    def update_fields(self):
        """ Update field values on embed form based on template """
        print('update fields called for ConstituentNodeEditEmbed')
        node = self.host
        self.label.setText(node.label)
        print('label: ', repr(node.label))
        self.synlabel.setText(node.get_syntactic_label())
        self.autolabel.setText(as_editable_html(node.autolabel))
        self.index.setText(node.index or '')

    def triangle_enabled(self):
        node = self.host
        if not node:
            return False
        elif not node.triangle_stack:
            return True
        elif node.triangle_stack[-1] == node:
            return True
        return False

    def synlabel_edited(self, *args, **kwargs):
        #print('synlabel edited')
        #print(args, kwargs)
        pass

    def synlabel_finished(self):
        text = self.synlabel.text()
        self.host.parse_edited_label('syntactic label', text)
        ctrl.forest.forest_edited()
        self.update_fields()

    def label_edited(self, *args, **kwargs):
        pass

    def label_finished(self):
        text = self.label.inode_text()
        self.host.parse_edited_label('node label', text)
        ctrl.forest.forest_edited()
        self.update_fields()

    def index_finished(self):
        text = self.index.text()
        self.host.parse_edited_label('index', text)
        ctrl.forest.forest_edited()
        self.update_fields()

    def submit_values(self):
        """ Possibly called if assuming we are in NodeEditEmbed. All of the changes in
        ConstituentNodeEditEmbed should take effect immediately, so separate submit is not needed.
        :return:
        """
        self.host.update_label()

    def focus_to_main(self):
        """ Find the main element to focus in this embed.
        :return:
        """
        m = ctrl.settings.get('label_text_mode')
        if m == g.SYN_LABELS or m == g.SYN_LABELS_FOR_LEAVES:
            self.synlabel.setFocus()
        elif m == g.NODE_LABELS_FOR_LEAVES or m == g.NODE_LABELS:
            self.label.setFocus()
        elif m == g.XBAR_LABELS:
            self.autolabel.setFocus()
Ejemplo n.º 2
0
    def __init__(self, parent, node):
        nname = node.display_name[0].lower()
        UIEmbed.__init__(self, parent, node, 'Edit ' + nname)
        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(self.top_row_layout)
        layout.addSpacing(4)
        ui_p = self._palette
        ui_s = QtGui.QPalette(ui_p)
        ui_s.setColor(QtGui.QPalette.Text, ctrl.cm.secondary())
        smaller_font = qt_prefs.get_font(g.MAIN_FONT)
        big_font = QtGui.QFont(smaller_font)
        big_font.setPointSize(big_font.pointSize() * 2)
        ed = node.get_editing_template()
        sortable = [(item.get('order', 100), key) for key, item in ed.items()]
        sortable.sort()
        field_names = [key for order, key in sortable]
        self.fields = {}
        self.resize_target = None
        hlayout = None

        # Generate edit elements based on data, expand this as necessary
        for field_name in field_names:
            d = ed.get(field_name, {})
            if d.get('hidden', False) or not self.host.check_conditions(d):
                continue
            tt = d.get('tooltip', '')
            itype = d.get('input_type', 'text')
            prefill = d.get('prefill', '')
            syntactic = d.get('syntactic', False)
            on_edit = d.get('on_edit', None)
            if on_edit and isinstance(on_edit, str):
                on_edit = getattr(node, on_edit, None)
            field_first = False
            field = None
            if itype == 'text':
                width = d.get('width', 140)
                field = EmbeddedLineEdit(self, tip=tt, font=big_font, prefill=prefill, on_edit=on_edit)
                field.setMaximumWidth(width)
            elif itype == 'textarea':
                self._disable_effect = True
                template_width = d.get('width', 0)
                field = EmbeddedTextarea(self, tip=tt, font=smaller_font, prefill=prefill, on_edit=on_edit)
                max_w = 200
                if node.user_size:
                    w = node.user_size[0]
                elif template_width:
                    w = template_width
                else:
                    w = node.label_object.document().idealWidth()
                field.setFixedWidth(min(w, max_w))
                self.resize_target = field
            elif itype == 'expandingtext':
                field = ExpandingTextArea(self,
                                          tip=tt,
                                          font=smaller_font,
                                          prefill=prefill, on_edit=on_edit)
                template_width = d.get('width', 0)
                if template_width:
                    field.setFixedWidth(template_width)
                self.resize_target = field
            elif itype == 'multibutton':
                # currently not used, radio button is better
                width = d.get('width', 200)
                op_func = d.get('option_function')
                op_func = getattr(self.host, op_func, None) or getattr(self.syntactic_object,
                                                                       op_func, None)
                field = EmbeddedMultibutton(self, options=op_func())
                field.setMaximumWidth(width)
            elif itype == 'checkbox':
                field = QtWidgets.QCheckBox(self)
            elif itype == 'radiobutton':
                width = d.get('width', 200)
                op_func = d.get('option_function')
                op_func = getattr(self.host, op_func, None) or \
                          getattr(self.syntactic_object, op_func, None)
                field = EmbeddedRadiobutton(self, options=op_func())
                field.setMaximumWidth(width)
                field_first = False
            elif itype == 'preview':
                field = PreviewLabel(self, tip=tt, font=smaller_font)
            else:
                raise NotImplementedError

            if field:
                action = d.get('select_action')
                if action:
                    self.ui_manager.connect_element_to_action(field, action)
                if syntactic:
                    field.setPalette(ui_s)
                else:
                    field.setPalette(ui_p)

            align = d.get('align', 'newline')
            if align == 'newline':
                # new hlayout means new line, but before starting a new hlayout,
                # end the previous one.
                if hlayout:
                    layout.addLayout(hlayout)
                hlayout = QtWidgets.QHBoxLayout()
            self.fields[field_name] = field
            if field_first:
                hlayout.addWidget(field)
            ui_name = d.get('name', field_name)
            if ui_name:
                if syntactic:
                    palette = ui_s
                else:
                    palette = ui_p
                make_label(ui_name, self, hlayout, tt, field, palette)
            if not field_first:
                hlayout.addWidget(field)
        if hlayout:
            layout.addLayout(hlayout)
        hlayout = QtWidgets.QHBoxLayout()
        self.enter_button = QtWidgets.QPushButton("Keep ↩")  # U+21A9 &#8617;
        self.enter_button.setParent(self)
        self.ui_manager.connect_element_to_action(self.enter_button, 'finish_editing_node')
        hlayout.addStretch(0)
        hlayout.addWidget(self.enter_button, 0, QtCore.Qt.AlignRight)
        if self.resize_target:
            self.resize_handle = ResizeHandle(self, self.resize_target)
            hlayout.addWidget(self.resize_handle, 0, QtCore.Qt.AlignRight)
        layout.addLayout(hlayout)
        self.setLayout(layout)
        self.update_embed()
        self.update_position()
        self.hide()
Ejemplo n.º 3
0
    def __init__(self, parent, node):
        nname = node.display_name[0].lower()
        UIEmbed.__init__(self, parent, node, 'Edit ' + nname)
        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(self.top_row_layout)
        layout.addSpacing(4)
        ui_p = self._palette
        ui_s = QtGui.QPalette(ui_p)
        ui_s.setColor(QtGui.QPalette.Text, ctrl.cm.secondary())
        smaller_font = qt_prefs.get_font(g.MAIN_FONT)
        big_font = QtGui.QFont(smaller_font)
        big_font.setPointSize(big_font.pointSize() * 2)
        ed = node.get_editing_template()
        sortable = [(item.get('order', 100), key) for key, item in ed.items()]
        sortable.sort()
        field_names = [key for order, key in sortable]
        self.fields = {}
        self.resize_target = None
        hlayout = None

        # Generate edit elements based on data, expand this as necessary
        for field_name in field_names:
            d = ed.get(field_name, {})
            if d.get('hidden', False) or not self.host.check_conditions(d):
                continue
            tt = d.get('tooltip', '')
            itype = d.get('input_type', 'text')
            prefill = d.get('prefill', '')
            syntactic = d.get('syntactic', False)
            on_edit = d.get('on_edit', None)
            if on_edit and isinstance(on_edit, str):
                on_edit = getattr(node, on_edit, None)
            field_first = False
            field = None
            if itype == 'text':
                width = d.get('width', 140)
                field = EmbeddedLineEdit(self,
                                         tip=tt,
                                         font=big_font,
                                         prefill=prefill,
                                         on_edit=on_edit)
                field.setMaximumWidth(width)
            elif itype == 'textarea':
                self._disable_effect = True
                template_width = d.get('width', 0)
                field = EmbeddedTextarea(self,
                                         tip=tt,
                                         font=smaller_font,
                                         prefill=prefill,
                                         on_edit=on_edit)
                max_w = 200
                if node.user_size:
                    w = node.user_size[0]
                elif template_width:
                    w = template_width
                else:
                    w = node.label_object.document().idealWidth()
                field.setFixedWidth(min(w, max_w))
                self.resize_target = field
            elif itype == 'expandingtext':
                field = ExpandingTextArea(self,
                                          tip=tt,
                                          font=smaller_font,
                                          prefill=prefill,
                                          on_edit=on_edit)
                template_width = d.get('width', 0)
                if template_width:
                    field.setFixedWidth(template_width)
                self.resize_target = field
            elif itype == 'multibutton':
                width = d.get('width', 200)
                op_func = d.get('option_function')
                op_func = getattr(self.host, op_func, None) or getattr(
                    self.syntactic_object, op_func, None)
                field = EmbeddedMultibutton(self, options=op_func())
                field.setMaximumWidth(width)
            elif itype == 'projection_buttons':
                width = d.get('width', 200)
                field = ProjectionButtons(self)
                field.setMaximumWidth(width)
            elif itype == 'checkbox':
                field = QtWidgets.QCheckBox(self)
            elif itype == 'radiobutton':
                width = d.get('width', 200)
                op_func = d.get('option_function')
                op_func = getattr(self.host, op_func, None) or \
                          getattr(self.syntactic_object, op_func, None)
                field = EmbeddedRadiobutton(self, options=op_func())
                field.setMaximumWidth(width)
                field_first = False
            elif itype == 'preview':
                field = PreviewLabel(self, tip=tt, font=smaller_font)
            elif itype == 'spinbox':
                field = QtWidgets.QSpinBox(self)
                field.setMinimum(d.get('min', -1))
                field.setMaximum(d.get('max', 4))
            else:
                raise NotImplementedError

            if field:
                action = d.get('select_action')
                if action:
                    connect_slot = getattr(field, 'connect_slot', None)
                    self.ui_manager.connect_element_to_action(
                        field, action, connect_slot=connect_slot)
                if syntactic:
                    field.setPalette(ui_s)
                else:
                    field.setPalette(ui_p)

            align = d.get('align', 'newline')
            if align == 'newline':
                # new hlayout means new line, but before starting a new hlayout,
                # end the previous one.
                if hlayout:
                    layout.addLayout(hlayout)
                hlayout = QtWidgets.QHBoxLayout()
            self.fields[field_name] = field
            if field_first:
                hlayout.addWidget(field)
            ui_name = d.get('name', field_name)
            if ui_name:
                if syntactic:
                    palette = ui_s
                else:
                    palette = ui_p
                make_label(ui_name, self, hlayout, tt, field, palette)
            if not field_first:
                hlayout.addWidget(field)
        if hlayout:
            layout.addLayout(hlayout)
        hlayout = QtWidgets.QHBoxLayout()
        self.enter_button = QtWidgets.QPushButton("Keep ↩")  # U+21A9 &#8617;
        self.enter_button.setParent(self)
        self.ui_manager.connect_element_to_action(self.enter_button,
                                                  'finish_editing_node')
        hlayout.addStretch(0)
        hlayout.addWidget(self.enter_button, 0, QtCore.Qt.AlignRight)
        if self.resize_target:
            self.resize_handle = ResizeHandle(self, self.resize_target)
            hlayout.addWidget(self.resize_handle, 0, QtCore.Qt.AlignRight)
        layout.addLayout(hlayout)
        self.setLayout(layout)
        self.update_embed()
        self.update_position()
        self.hide()