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()
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 ↩ 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()
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 ↩ 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()