class CastWindow(QWidget): def __init__(self, parent, mode='normal'): super().__init__() self.parent = parent self.mode = mode if self.mode == 'wide': self.MAX_CAST_NUM = 12 self.num_col = 6 self.num_row = 2 self.cast_num = 12 elif self.mode == 'long': self.MAX_CAST_NUM = 12 self.cast_num = 12 else: self.MAX_CAST_NUM = 10 self.cast_num = 10 self.cast_labels = [CastLabel(self) for i in range(self.MAX_CAST_NUM)] print('init Cast Window.') self.initUI() def initUI(self): if self.mode == 'wide': self.layout = QGridLayout() for i in range(self.num_col): self.layout.setColumnStretch(i, 1) for i in range(self.num_row): self.layout.setRowStretch(i, 1) positions = [(i, j) for i in range(self.num_row) for j in range(self.num_col)] for i in range(self.cast_num): if i < self.MAX_CAST_NUM: self.layout.addWidget(self.cast_labels[i], *positions[i]) else: self.layout = QVBoxLayout() for i in range(self.cast_num): self.layout.addWidget(self.cast_labels[i]) self.setLayout(self.layout) def update_cast(self, cast_list): self.cast_num = len(cast_list) for i in range(self.cast_num): self.cast_labels[i].reset_pixmp(cast_list[i]) self.cast_labels[i].seltectable = True for i in range(self.cast_num, self.MAX_CAST_NUM): self.cast_labels[i].reset_pixmp() self.cast_labels[i].seltectable = False self.update() def seletected_changed(self): self.parent.cast_selected_changed() def clean_seltected(self): for i in range(self.cast_num): self.cast_labels[i].isSelected = False self.update() def set_selected_idx(self, idx): if idx < self.cast_num and idx >= 0: self.cast_labels[idx].isSelected = True else: self.clean_seltected() self.update() def get_seletectd_idx(self): sidx = -1 for i in range(self.cast_num): if self.cast_labels[i].isSelected: sidx = i return sidx
def __init__( self, session, name, prox_word, cmd_name, color, radius, hbond_allowance, overlap_cutoff, has_apply_button, *, settings_name="", # settings_name values: # empty string: remembered across sessions and the same as for the main contacts/clashes # GUI # custom string (e.g. "rotamers"): remembered across sessions and specific to your # interface, not shared with other contacts/clashes GUIs. The string "contacts GUI" # or "clashes GUI" will be appended to the provided string to yield the final settings # name. # None: not remembered across sessions # # The settings will be saved when get_command() is called. The defaults for the # settings will be the same as the values provided for the arguments below (i.e. # can be overriden by providing explicit values when calling this function). # # Controls configured to not show in the interface will not have their corresponding # keyword/value added to the command returned by get_command, nor will they have their # settings value changed/saved. If needed, you will have to add the keyword/value to # the command yourself. # # Your tool needs to call the GUI's destroy() method when it's deleted attr_name=defaults["attr_name"], bond_separation=defaults["bond_separation"], continuous=False, dashes=None, distance_only=None, inter_model=True, inter_submodel=False, intra_model=True, intra_mol=defaults["intra_mol"], intra_res=defaults["intra_res"], log=defaults["action_log"], make_pseudobonds=defaults["action_pseudobonds"], res_separation=None, restrict="any", reveal=False, save_file=None, select=defaults["action_select"], set_attrs=defaults["action_attr"], show_dist=False, summary=True, test_atoms=None, # what controls to show in the interface # # note that if 'test_atoms' is not None, then the selection-restriction control will be omitted # regardless of the 'show_restrict' value show_attr_name=True, show_bond_separation=True, show_checking_frequency=True, show_color=True, show_dashes=True, show_distance_only=True, show_hbond_allowance=True, show_inter_model=True, show_inter_submodel=False, show_intra_model=True, show_intra_mol=True, show_intra_res=True, show_log=True, show_make_pseudobonds=True, show_name=True, show_overlap_cutoff=True, show_radius=True, show_res_separation=True, show_restrict=True, show_reveal=True, show_save_file=True, show_select=True, show_set_attrs=True, show_show_dist=True, show_summary=False): self.session = session self.cmd_name = cmd_name from inspect import getargvalues, currentframe arg_names, var_args, var_kw, frame_dict = getargvalues(currentframe()) settings_defaults = {} self.show_values = {} for arg_name in arg_names: if not arg_name.startswith( 'show_') or 'show_' + arg_name in arg_names: settings_defaults[arg_name] = frame_dict[arg_name] else: self.show_values[arg_name[5:]] = frame_dict[arg_name] if settings_name is None: self.settings = settings = None else: self.settings = settings = _get_settings(session, settings_name, settings_defaults, cmd_name) final_val = {} for def_name in settings_defaults.keys(): final_val[def_name] = getattr( settings, def_name) if settings else frame_dict[def_name] super().__init__() from PyQt5.QtWidgets import QVBoxLayout, QGridLayout, QGroupBox, QLabel, QPushButton, QButtonGroup from PyQt5.QtWidgets import QRadioButton, QAbstractButton, QHBoxLayout, QDoubleSpinBox, QMenu from PyQt5.QtWidgets import QSpinBox, QCheckBox from PyQt5.QtCore import Qt layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.setSizeConstraint(QVBoxLayout.SetFixedSize) self.setLayout(layout) from chimerax.core.commands import plural_of self.prox_word = prox_word self.prox_words = prox_words = plural_of(prox_word) if test_atoms is not None: show_restrict = False show_bool_params = show_intra_model or show_intra_mol or show_intra_res or show_inter_model \ or show_inter_submodel if show_overlap_cutoff or show_hbond_allowance or show_restrict or show_bond_separation \ or show_bool_params: group = QGroupBox("Interaction parameters") layout.addWidget(group) group_layout = QVBoxLayout() group_layout.setContentsMargins(0, 0, 0, 0) group_layout.setSpacing(5) group.setLayout(group_layout) overlap_widgets = [] distance_only_widgets = [] if (show_overlap_cutoff or show_hbond_allowance) and show_distance_only: test_type_layout = QGridLayout() test_type_layout.setContentsMargins(0, 0, 0, 0) test_type_layout.setSpacing(0) test_type_layout.setColumnStretch(1, 1) group_layout.addLayout(test_type_layout) overlap_rows = show_overlap_cutoff + show_hbond_allowance self.overlap_radio = QRadioButton("") test_type_layout.addWidget(self.overlap_radio, 0, 0, overlap_rows, 1) self.distance_radio = QRadioButton("") test_type_layout.addWidget(self.distance_radio, overlap_rows, 0) def enable_widgets(enabled, enabled_widgets, disabled_widgets): for ew in enabled_widgets: ew.setEnabled(enabled) for dw in disabled_widgets: dw.setEnabled(not enabled) self.overlap_radio.toggled.connect( lambda chk, *, ew=overlap_widgets, dw= distance_only_widgets, f=enable_widgets: f(chk, ew, dw)) self.distance_radio.toggled.connect( lambda chk, *, ew=distance_only_widgets, dw= overlap_widgets, f=enable_widgets: f(chk, ew, dw)) row = 0 if show_overlap_cutoff: cutoff_args = (row, 1) row += 1 if show_hbond_allowance: allowance_args = (row, 1) row += 1 distance_args = (row, 1) else: test_type_layout = group_layout cutoff_args = allowance_args = distance_args = () if show_overlap_cutoff: overlap_layout = QHBoxLayout() overlap_layout.setContentsMargins(0, 0, 0, 0) overlap_layout.setSpacing(0) test_type_layout.addLayout(overlap_layout, *cutoff_args) lab = QLabel( "Find pairs of atoms with VDW overlap \N{GREATER-THAN OR EQUAL TO}" ) overlap_widgets.append(lab) overlap_layout.addWidget(lab) self.overlap_spinbox = QDoubleSpinBox() self.overlap_spinbox.setDecimals(2) self.overlap_spinbox.setSingleStep(0.1) self.overlap_spinbox.setRange(-99, 99) self.overlap_spinbox.setValue(final_val['overlap_cutoff']) #self.overlap_spinbox.setSuffix('\N{ANGSTROM SIGN}') overlap_widgets.append(self.overlap_spinbox) overlap_layout.addWidget(self.overlap_spinbox) lab2 = QLabel("\N{ANGSTROM SIGN}") overlap_widgets.append(lab2) overlap_layout.addWidget(lab2, stretch=1, alignment=Qt.AlignLeft) if show_hbond_allowance: hbond_layout = QHBoxLayout() hbond_layout.setContentsMargins(0, 0, 0, 0) hbond_layout.setSpacing(0) test_type_layout.addLayout(hbond_layout, *allowance_args) lab = QLabel("Subtract") overlap_widgets.append(lab) hbond_layout.addWidget(lab) self.hbond_spinbox = QDoubleSpinBox() self.hbond_spinbox.setDecimals(2) self.hbond_spinbox.setSingleStep(0.1) self.hbond_spinbox.setRange(-99, 99) self.hbond_spinbox.setValue(final_val['hbond_allowance']) #self.hbond_spinbox.setSuffix('\N{ANGSTROM SIGN}') overlap_widgets.append(self.hbond_spinbox) hbond_layout.addWidget(self.hbond_spinbox) lab = QLabel("from overlap for potentially H-bonding pairs") overlap_widgets.append(lab) hbond_layout.addWidget(lab, stretch=1, alignment=Qt.AlignLeft) if show_distance_only: distance_layout = QHBoxLayout() distance_layout.setContentsMargins(0, 0, 0, 0) distance_layout.setSpacing(0) test_type_layout.addLayout(distance_layout, *distance_args) lab = QLabel( "Find pairs of atoms with center-center distance \N{LESS-THAN OR EQUAL TO}" ) distance_only_widgets.append(lab) distance_layout.addWidget(lab) self.dist_only_spinbox = QDoubleSpinBox() self.dist_only_spinbox.setDecimals(2) self.dist_only_spinbox.setSingleStep(0.1) self.dist_only_spinbox.setRange(0, 1000000) val = 4.0 if final_val['distance_only'] is None else final_val[ 'distance_only'] self.dist_only_spinbox.setValue(val) #self.dist_only_spinbox.setSuffix('\N{ANGSTROM SIGN}') distance_only_widgets.append(self.dist_only_spinbox) distance_layout.addWidget(self.dist_only_spinbox, alignment=Qt.AlignLeft) lab2 = QLabel("\N{ANGSTROM SIGN}") distance_only_widgets.append(lab2) distance_layout.addWidget(lab2, stretch=1, alignment=Qt.AlignLeft) if overlap_widgets and distance_only_widgets: if distance_only is None: self.overlap_radio.setChecked(True) enable_widgets(False, distance_only_widgets, overlap_widgets) else: self.distance_radio.setChecked(True) enable_widgets(True, distance_only_widgets, overlap_widgets) if show_restrict: restrict_options = OptionsPanel(sorting=False, scrolled=False, contents_margins=(0, 0, 0, 0)) group_layout.addWidget(restrict_options, alignment=Qt.AlignLeft) if show_restrict: self.sel_restrict_option = make_optional( AtomPairRestrictOption)("Limit by selection", None, None, atom_word="end") restrict_options.add_option(self.sel_restrict_option) if show_bond_separation: bond_sep_layout = QHBoxLayout() bond_sep_layout.setContentsMargins(0, 0, 0, 0) bond_sep_layout.setSpacing(0) group_layout.addLayout(bond_sep_layout) bond_sep_layout.addWidget( QLabel("Ignore interactions between atoms")) self.bond_sep_button = QPushButton() bond_sep_layout.addWidget(self.bond_sep_button) bond_sep_menu = QMenu(self) for bond_sep in range(2, 6): bond_sep_menu.addAction(str(bond_sep)) bond_sep_menu.triggered.connect( lambda action, but=self.bond_sep_button: but.setText( action.text())) self.bond_sep_button.setMenu(bond_sep_menu) self.bond_sep_button.setText(str(bond_separation)) bond_sep_layout.addWidget(QLabel("or fewer bonds apart"), stretch=1, alignment=Qt.AlignLeft) if show_res_separation: res_sep_layout = QHBoxLayout() res_sep_layout.setContentsMargins(0, 0, 0, 0) #res_sep_layout.setSpacing(0) group_layout.addLayout(res_sep_layout) self.res_sep_checkbox = QCheckBox( "Ignore interactions between residues <") final_rs_val = final_val['res_separation'] self.res_sep_checkbox.setChecked(final_rs_val is not None) res_sep_layout.addWidget(self.res_sep_checkbox) val = 5 if final_rs_val is None else final_rs_val self.res_sep_spinbox = rs_box = QSpinBox() rs_box.setMinimum(1) rs_box.setValue(val) res_sep_layout.addWidget(rs_box) res_sep_layout.addWidget(QLabel("apart in sequence"), stretch=1, alignment=Qt.AlignLeft) if show_bool_params: bool_param_options = OptionsPanel(sorting=False, scrolled=False, contents_margins=(10, 0, 10, 0)) group_layout.addWidget(bool_param_options, alignment=Qt.AlignCenter) if show_inter_model: self.inter_model_option = BooleanOption( "Include intermodel", None if settings else inter_model, None, attr_name="inter_model", settings=settings) bool_param_options.add_option(self.inter_model_option) if show_inter_submodel: self.inter_submodel_option = BooleanOption( "Include intersubmodel", None if settings else inter_submodel, None, attr_name="inter_submodel", settings=settings) bool_param_options.add_option(self.inter_submodel_option) if show_intra_model: self.intra_model_option = BooleanOption( "Include intramodel", None if settings else intra_model, None, attr_name="intra_model", settings=settings) bool_param_options.add_option(self.intra_model_option) if show_intra_mol: self.intra_mol_option = BooleanOption( "Include intramolecule", None if settings else intra_mol, None, attr_name="intra_mol", settings=settings) bool_param_options.add_option(self.intra_mol_option) if show_intra_res: self.intra_res_option = BooleanOption( "Include intraresidue", None if settings else intra_res, None, attr_name="intra_res", settings=settings) bool_param_options.add_option(self.intra_res_option) if show_select or show_make_pseudobonds or show_color or show_dashes or show_radius \ or show_show_dist or show_name or show_reveal or show_attr_name or show_set_attrs or show_log \ or show_save_file: group = QGroupBox("Treatment of results") layout.addWidget(group) group_layout = QVBoxLayout() group_layout.setContentsMargins(0, 0, 0, 0) group_layout.setSpacing(5) group.setLayout(group_layout) treatment_options = OptionsPanel(sorting=False, scrolled=False, contents_margins=(10, 0, 10, 0)) group_layout.addWidget(treatment_options) if show_select: self.select_option = BooleanOption( "Select atoms", None if settings else select, None, attr_name="select", settings=settings) treatment_options.add_option(self.select_option) if show_make_pseudobonds: if show_color or show_dashes or show_radius or show_show_dist or show_name: # checkable group self.make_pseudobonds_widget, sub_options = treatment_options.add_option_group( group_label="Display as pseudobonds", checked=final_val['make_pseudobonds'], contents_margins=(10, 0, 10, 0), sorting=False) subgroup_layout = QVBoxLayout() subgroup_layout.setContentsMargins(0, 0, 0, 0) subgroup_layout.setSpacing(5) self.make_pseudobonds_widget.setLayout(subgroup_layout) subgroup_layout.addWidget(sub_options) if show_color: self.color_option = ColorOption( "Color", None if settings else color, None, attr_name="color", settings=settings) sub_options.add_option(self.color_option) if show_radius: self.radius_option = FloatOption( "Radius", None if settings else radius, None, attr_name="radius", settings=settings) sub_options.add_option(self.radius_option) if show_dashes: self.dashes_option = IntOption( "Dashes", None if settings else dashes, None, attr_name="dashes", min=0, settings=settings) sub_options.add_option(self.dashes_option) if show_show_dist: self.show_dist_option = BooleanOption( "Distance label", None if settings else show_dist, None, attr_name="show_dist", settings=settings) sub_options.add_option(self.show_dist_option) if show_name: self.name_option = StringOption( "Group name", name, None) sub_options.add_option(self.name_option) else: # boolean self.make_pseudobonds_widget = BooleanOption( "Draw pseudobonds", None if settings else make_pseudobonds, None, attr_name="make_pseudobonds", settings=settings) treatment_options.add_option(self.make_pseudobonds_widget) else: if show_color: self.color_option = ColorOption( "Pseudobond color", None if settings else color, None, attr_name="color", settings=settings) treatment_options.add_option(self.color_option) if show_radius: self.radius_option = FloatOption( "Pseudobond radius", None if settings else radius, None, attr_name="radius", settings=settings) treatment_options.add_option(self.radius_option) if show_dashes: self.dashes_option = IntOption( "Pseudobond dashes", None if settings else dashes, None, attr_name="dashes", min=0, settings=settings) sub_options.add_option(self.dashes_option) if show_show_dist: self.show_dist_option = BooleanOption( "Pseudobond distance label", None if settings else show_dist, None, attr_name="show_dist", settings=settings) sub_options.add_option(self.show_dist_option) if show_name: self.name_option = StringOption("Pseudobond group name", name, None) sub_options.add_option(self.name_option) if show_reveal: self.reveal_option = BooleanOption( "Reveal atoms of interacting residues", None if settings else reveal, None, attr_name="reveal", settings=settings) treatment_options.add_option(self.reveal_option) if show_set_attrs: if show_attr_name: combo_option = make_optional(StringOption) option = self.attr_name_option = combo_option( "Assign atomic attribute named", final_val['attr_name'], None) if not final_val['set_attrs']: # done this way so that attr name is not blank option.value = None else: option = self.set_attrs_option = BooleanOption( "Assign attribute", final_val['set_attrs'], None) treatment_options.add_option(option) elif show_attr_name: self.attr_name_option = StringOption("Attribute name", final_val['attr_name'], None) treatment_options.add_option(self.attr_name_option) if show_log or show_save_file: group = QGroupBox("Write information to:") layout.addWidget(group) info_layout = QVBoxLayout() info_layout.setContentsMargins(0, 0, 0, 0) info_layout.setSpacing(0) group.setLayout(info_layout) info_options = OptionsPanel(sorting=False, scrolled=False, contents_margins=(0, 0, 0, 0)) info_layout.addWidget(info_options) if show_log: self.log_option = BooleanOption("Log", None if settings else log, None, attr_name="log", settings=settings) info_options.add_option(self.log_option) if show_save_file: self.save_file_option = BooleanOption("File", False, None) info_options.add_option(self.save_file_option) if show_summary: self.summary_option = BooleanOption( "Log total number of %s" % prox_words, None if settings else summary, None, attr_name="summary", settings=settings) treatment_options.add_option(self.summary_option) if show_checking_frequency: group = QGroupBox("Frequency of checking") layout.addWidget(group) group_layout = QGridLayout() group_layout.setContentsMargins(0, 0, 0, 0) group_layout.setSpacing(5) group_layout.setColumnStretch(0, 1) group_layout.setColumnStretch(3, 1) group.setLayout(group_layout) group_layout.addWidget(QLabel("Check..."), 0, 1, 2, 1, alignment=Qt.AlignRight | Qt.AlignVCenter) self.ok_radio = QRadioButton( "when OK%s clicked" % ("/Apply" if has_apply_button else "")) self.ok_radio.setChecked(True) group_layout.addWidget(self.ok_radio, 0, 2, alignment=Qt.AlignLeft) self.ok_radio.toggled.connect(self._checking_change) group_layout.addWidget( QRadioButton("continuously (until dialog closed)"), 1, 2, alignment=Qt.AlignLeft)