Ejemplo n.º 1
0
    def __init__(self, gui_class, help_url, *args, **kw):
        super().__init__(*args, **kw)
        self.help = help_url

        from chimerax.ui import MainToolWindow
        self.tool_window = tw = MainToolWindow(self)
        parent = tw.ui_area
        from PyQt5.QtWidgets import QVBoxLayout, QDialogButtonBox
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        parent.setLayout(layout)
        self.gui = gui_class(self.session, has_apply_button=True)
        layout.addWidget(self.gui)

        from PyQt5.QtWidgets import QDialogButtonBox as qbbox
        bbox = qbbox(qbbox.Ok | qbbox.Apply | qbbox.Close | qbbox.Help)
        bbox.accepted.connect(self.run_command)
        bbox.button(qbbox.Apply).clicked.connect(self.run_command)
        bbox.accepted.connect(
            self.delete)  # slots executed in the order they are connected
        bbox.rejected.connect(self.delete)
        if self.help:
            from chimerax.core.commands import run
            bbox.helpRequested.connect(lambda run=run, ses=self.session: run(
                ses, "help " + self.help))
        else:
            bbox.button(qbbox.Help).setEnabled(False)
        layout.addWidget(bbox)

        tw.manage(placement=None)
Ejemplo n.º 2
0
    def __init__(self, session, tool_name):
        ToolInstance.__init__(self, session, tool_name)
        from chimerax.ui import MainToolWindow
        self.tool_window = tw = MainToolWindow(self)
        parent = tw.ui_area
        from PyQt5.QtWidgets import QVBoxLayout, QDialogButtonBox
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        parent.setLayout(layout)
        from .gui import HBondsGUI
        self.gui = HBondsGUI(session, show_model_restrict=False)
        layout.addWidget(self.gui)

        from PyQt5.QtWidgets import QDialogButtonBox as qbbox
        bbox = qbbox(qbbox.Ok | qbbox.Apply | qbbox.Close | qbbox.Help)
        bbox.accepted.connect(self.run_hbonds)
        bbox.button(qbbox.Apply).clicked.connect(self.run_hbonds)
        bbox.accepted.connect(
            self.delete)  # slots executed in the order they are connected
        bbox.rejected.connect(self.delete)
        from chimerax.core.commands import run
        bbox.helpRequested.connect(
            lambda run=run, ses=session: run(ses, "help " + self.help))
        layout.addWidget(bbox)

        tw.manage(placement=None)
Ejemplo n.º 3
0
    def __init__(self, session, tool_name):
        ToolInstance.__init__(self, session, tool_name)
        self.display_name = "Show Chain Sequence"
        self.settings = SequencesSettings(session, "ChainSequences")

        from chimerax.ui import MainToolWindow
        self.tool_window = tw = MainToolWindow(self)
        parent = tw.ui_area

        from PyQt5.QtWidgets import QVBoxLayout, QCheckBox
        layout = QVBoxLayout()
        parent.setLayout(layout)
        from chimerax.atomic.widgets import ChainListWidget
        self.chain_list = ChainListWidget(session, group_identical=self.settings.grouping,
            autoselect="first")
        self.chain_list.value_changed.connect(self._update_show_button)
        layout.addWidget(self.chain_list, stretch=1)

        self.grouping_button = QCheckBox("Group identical sequences")
        self.grouping_button.setChecked(self.settings.grouping)
        self.grouping_button.stateChanged.connect(self._grouping_change)
        layout.addWidget(self.grouping_button)

        from PyQt5.QtWidgets import QDialogButtonBox as qbbox
        bbox = qbbox()
        self._show_button = bbox.addButton("Show", qbbox.AcceptRole)
        bbox.addButton(qbbox.Cancel)
        #bbox.addButton(qbbox.Help)
        bbox.accepted.connect(self.show_seqs)
        bbox.accepted.connect(self.delete) # slots executed in the order they are connected
        bbox.rejected.connect(self.delete)
        from chimerax.core.commands import run
        bbox.helpRequested.connect(lambda run=run, ses=session: run(ses, "help " + self.help))
        layout.addWidget(bbox)

        self._update_show_button()

        tw.manage(placement=None)
Ejemplo n.º 4
0
    def __init__(self, *, auto_multiline_headers=True, column_control_info=None, allow_user_sorting=True,
            settings_attr=None):
        """ 'auto_multiline_headers' controls whether header titles can be split into multiple
            lines on word boundaries.

            'allow_user_sorting' controls whether mouse clicks on column headers will sort the
            columns.

            'column_control_info', if provided, is used to populate either a menu or widget with
            check box entries or check boxes (respectively) to control which columns are displayed.
            For a menu the value should be:
                (QMenu instance, chimerax.core.settings.Settings instance, defaults dictionary,
                  fallback default [, optional display callback])
            For a widget the value is:
                (QWidget instance, chimerax.core.settings.Settings instance, defaults dictionary,
                  fallback default, display callback, number of check box columns, show global buttons)
            The Settings instance will be used to remember the displayed column preferences (as
            an attribute given by 'settings_attr', which defaults to DEFAULT_SETTINGS_ATTR and which
            should be declared as 'EXPLICIT_SAVE').  The defaults dictionary controls whether the
            column is shown by default, which column titles as keys and booleans as values (True =
            displayed).  The fallback default (a boolean) is for columns missing from the defaults
            dictionary.  The display callback, if not None, is called when a column is configured
            in/out of the table.  It is called with a single argument: the ItemColumn instance (whose
            'display' attribute corresponds to the state _after_ the change).  Widget-style control
            areas have an additional field, which is the number of check box columns.  If None,
            the number will be determined automatically (approx. square root of number of check buttons,
            'show global buttons' determines whether the "Show All", etc.. buttons are added.  Typically
            should be set to True for tables with a fixed set of columns and False for variable sets.
        """
        self._table_model = None
        self._columns = []
        self._data = []
        self._allow_user_sorting = allow_user_sorting
        self._auto_multiline_headers = auto_multiline_headers
        self._column_control_info = column_control_info
        self._settings_attr = self.DEFAULT_SETTINGS_ATTR if settings_attr is None else settings_attr
        self._pending_columns = []
        if column_control_info:
            self._checkables = {}
            from PyQt5.QtWidgets import QVBoxLayout, QGridLayout, QHBoxLayout, QWidget, QLabel
            # QMenu is also a QWidget, so can't test isinstance(QWidget)...
            if not isinstance(column_control_info[0], QMenu):
                from PyQt5.QtCore import Qt
                main_layout = QVBoxLayout()
                column_control_info[0].setLayout(main_layout)
                self._col_checkbox_layout = QGridLayout()
                self._col_checkbox_layout.setContentsMargins(0,0,0,0)
                self._col_checkbox_layout.setSpacing(0)
                main_layout.addLayout(self._col_checkbox_layout)
                self._col_checkboxes = []
                if column_control_info[-1]:
                    from PyQt5.QtWidgets import QDialogButtonBox as qbbox
                    buttons_widget = QWidget()
                    main_layout.addWidget(buttons_widget, alignment=Qt.AlignLeft)
                    buttons_layout = QHBoxLayout()
                    buttons_layout.setContentsMargins(0,0,0,0)
                    buttons_widget.setLayout(buttons_layout)
                    buttons_layout.addWidget(QLabel("Show columns"))
                    bbox = qbbox()
                    buttons_layout.addWidget(bbox)
                    bbox.addButton("All", qbbox.ActionRole).clicked.connect(self._show_all_columns)
                    bbox.addButton("Default", qbbox.ActionRole).clicked.connect(self._show_default)
                    bbox.addButton("Standard", qbbox.ActionRole).clicked.connect(self._show_standard)
                    bbox.addButton("Set Default", qbbox.ActionRole).clicked.connect(self._set_default)
        self._highlighted = set()
        super().__init__()
Ejemplo n.º 5
0
    def __init__(self, session, parent, seq):
        super().__init__(parent)
        self.setSizeGripEnabled(True)

        layout = QVBoxLayout()
        layout.setContentsMargins(0,0,0,0)
        layout.setSpacing(2)
        self.setLayout(layout)

        self.table = QTableWidget(len(seq), 3)
        self.table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.table.setHorizontalHeaderLabels(["Res", "\N{GREEK CAPITAL LETTER PHI}",
            "\N{GREEK CAPITAL LETTER PSI}"])
        self.table.verticalHeader().hide()
        self.table.setSelectionBehavior(QTableWidget.SelectRows)
        for i, c in enumerate(seq):
            item = QTableWidgetItem(c)
            item.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(i, 0, item)
            self.table.setItem(i, 1, QTableWidgetItem(""))
            self.table.setItem(i, 2, QTableWidgetItem(""))
        layout.addWidget(self.table, stretch=1)

        phi_psi_layout = QHBoxLayout()
        phi_psi_layout.setContentsMargins(0,0,0,0)
        phi_psi_layout.setSpacing(2)
        set_button = QPushButton("Set")
        set_button.setDefault(False)
        set_button.clicked.connect(self._set_table)
        phi_psi_layout.addWidget(set_button, alignment=Qt.AlignRight)
        angle_range = QDoubleValidator(-180.0, 180.0, 1)
        phi_psi_layout.addWidget(QLabel("selected rows to \N{GREEK CAPITAL LETTER PHI}:"),
            alignment=Qt.AlignRight)
        self.phi_entry = QLineEdit()
        self.phi_entry.setMaximumWidth(45)
        self.phi_entry.setValidator(angle_range)
        phi_psi_layout.addWidget(self.phi_entry, alignment=Qt.AlignLeft)
        phi_psi_layout.addWidget(QLabel("\N{GREEK CAPITAL LETTER PSI}:"), alignment=Qt.AlignRight)
        self.psi_entry = QLineEdit()
        self.psi_entry.setMaximumWidth(45)
        self.psi_entry.setValidator(angle_range)
        phi_psi_layout.addWidget(self.psi_entry, alignment=Qt.AlignLeft)
        container = QWidget()
        container.setLayout(phi_psi_layout)
        layout.addWidget(container, alignment=Qt.AlignCenter)

        seed_option = PhiPsiOption("Seed above \N{GREEK CAPITAL LETTER PHI}/"
            "\N{GREEK CAPITAL LETTER PSI} with values for:",
            PhiPsiOption.values[0], self._seed_phi_psi)
        seed_widget = OptionsPanel(scrolled=False, contents_margins=(1,2,1,2))
        seed_widget.add_option(seed_option)
        layout.addWidget(seed_widget)

        lib_chain_layout = QHBoxLayout()
        lib_chain_layout.setContentsMargins(0,0,0,0)
        lib_chain_layout.setSpacing(2)
        lib_chain_layout.addWidget(QLabel("Rotamer library:"), alignment=Qt.AlignRight)
        self.rot_lib_button = session.rotamers.library_name_menu()
        lib_chain_layout.addWidget(self.rot_lib_button, alignment=Qt.AlignLeft)
        lib_chain_layout.addWidget(QLabel("chain ID:"), alignment=Qt.AlignRight)
        self.chain_entry = QLineEdit()
        self.chain_entry.setPlaceholderText("auto")
        self.chain_entry.setMaximumWidth(35)
        lib_chain_layout.addWidget(self.chain_entry, alignment=Qt.AlignLeft)
        container = QWidget()
        container.setLayout(lib_chain_layout)
        layout.addWidget(container, alignment=Qt.AlignCenter)

        from PyQt5.QtWidgets import QDialogButtonBox as qbbox
        bbox = qbbox(qbbox.Ok | qbbox.Cancel)
        bbox.accepted.connect(self.accept)
        bbox.rejected.connect(self.reject)
        layout.addWidget(bbox)

        self._seed_phi_psi(seed_option)
        self._set_table()
Ejemplo n.º 6
0
 def _show_subdialog(self, sd_type):
     if sd_type == "Density":
         from chimerax.map import Volume
         volumes = [m for m in self.session.models if isinstance(m, Volume)]
         if not volumes:
             raise UserError("Must open a volume/map file first!")
         if len(volumes) == 1:
             self._eval_vol(volumes[0])
             return
     if sd_type not in self.subdialogs:
         self.subdialogs[
             sd_type] = sd = self.tool_window.create_child_window(
                 "Add %s Column" % sd_type)
         from PyQt5.QtWidgets import QVBoxLayout, QDialogButtonBox as qbbox
         layout = QVBoxLayout()
         sd.ui_area.setLayout(layout)
         if sd_type == "H-Bonds":
             from chimerax.hbonds.gui import HBondsGUI
             sd.hbonds_gui = HBondsGUI(self.session,
                                       settings_name="rotamers",
                                       reveal=True,
                                       show_inter_model=False,
                                       show_intra_model=False,
                                       show_intra_mol=False,
                                       show_intra_res=False,
                                       show_model_restrict=False,
                                       show_bond_restrict=False,
                                       show_save_file=False)
             layout.addWidget(sd.hbonds_gui)
         elif sd_type == "Clashes":
             from chimerax.clashes.gui import ClashesGUI
             sd.clashes_gui = ClashesGUI(self.session,
                                         False,
                                         settings_name="rotamers",
                                         radius=0.075,
                                         show_restrict=False,
                                         show_bond_separation=False,
                                         show_res_separation=False,
                                         show_inter_model=False,
                                         show_intra_model=False,
                                         show_intra_res=False,
                                         show_intra_mol=False,
                                         show_attr_name=False,
                                         show_set_attrs=False,
                                         show_checking_frequency=False,
                                         restrict="cross",
                                         bond_separation=0,
                                         reveal=True,
                                         show_save_file=False)
             layout.addWidget(sd.clashes_gui)
         else:  # Density
             from chimerax.ui.widgets import ModelListWidget
             from PyQt5.QtWidgets import QFormLayout
             density_layout = QFormLayout()
             layout.addLayout(density_layout)
             sd.vol_list = ModelListWidget(self.session,
                                           selection_mode='single',
                                           class_filter=Volume)
             density_layout.addRow("Select density:", sd.vol_list)
         bbox = qbbox(qbbox.Ok | qbbox.Close | qbbox.Help)
         bbox.accepted.connect(
             lambda sdt=sd_type: self._process_subdialog(sdt))
         bbox.accepted.connect(lambda sd=sd: setattr(sd, 'shown', False))
         bbox.rejected.connect(lambda sd=sd: setattr(sd, 'shown', False))
         layout.addWidget(bbox)
         sd.manage(placement=None)
     else:
         self.subdialogs[sd_type].title = "Update %s Column" % sd_type
     self.subdialogs[sd_type].shown = True
Ejemplo n.º 7
0
    def __init__(self, session, tool_name):
        ToolInstance.__init__(self, session, tool_name)
        from chimerax.ui import MainToolWindow
        self.tool_window = tw = MainToolWindow(self)
        tw.title = "Choose Rotamer Parameters"
        parent = tw.ui_area
        from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QLabel, QGroupBox
        from PyQt5.QtCore import Qt
        self.layout = layout = QVBoxLayout()
        parent.setLayout(layout)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(QLabel("Show rotamers for selected residues..."),
                         alignment=Qt.AlignCenter)

        self.rot_lib_option = session.rotamers.library_name_option()(
            "Rotamer library", None, self._lib_change_cb)

        from chimerax.ui.options import EnumOption, OptionsPanel
        self.rot_lib = session.rotamers.library(self.rot_lib_option.value)
        res_name_list = self.lib_res_list()

        class ResTypeOption(EnumOption):
            values = res_name_list

        def_res_type = self._sel_res_type() or res_name_list[0]
        self.res_type_option = ResTypeOption("Rotamer type", def_res_type,
                                             None)

        opts = OptionsPanel(scrolled=False, contents_margins=(0, 0, 3, 3))
        opts.add_option(self.res_type_option)
        opts.add_option(self.rot_lib_option)
        layout.addWidget(opts, alignment=Qt.AlignCenter)

        self.lib_description = QLabel(self.rot_lib.description)
        layout.addWidget(self.lib_description, alignment=Qt.AlignCenter)

        self.rot_description_box = QGroupBox("Unusual rotamer codes")
        self.rot_description = QLabel("")
        box_layout = QVBoxLayout()
        box_layout.setContentsMargins(10, 0, 10, 0)
        box_layout.addWidget(self.rot_description)
        self.rot_description_box.setLayout(box_layout)
        layout.addWidget(self.rot_description_box, alignment=Qt.AlignCenter)
        self._update_rot_description()

        self.citation_widgets = {}
        cw = self.citation_widgets[self.rot_lib_option.value] = self.citation_widgets['showing'] \
            = self._make_citation_widget()
        if cw:
            layout.addWidget(cw, alignment=Qt.AlignCenter)

        from PyQt5.QtWidgets import QDialogButtonBox as qbbox
        self.bbox = bbox = qbbox(qbbox.Ok | qbbox.Apply | qbbox.Close
                                 | qbbox.Help)
        bbox.accepted.connect(self.launch_rotamers)
        bbox.button(qbbox.Apply).clicked.connect(self.launch_rotamers)
        bbox.accepted.connect(
            self.delete)  # slots executed in the order they are connected
        bbox.rejected.connect(self.delete)
        from chimerax.core.commands import run
        bbox.helpRequested.connect(
            lambda run=run, ses=session: run(ses, "help " + self.help))
        layout.addWidget(bbox)

        tw.manage(placement=None)
Ejemplo n.º 8
0
    def finalize_init(self, mgr, res_type, rot_lib, *, table_info=None):
        self.mgr = mgr
        self.res_type = res_type
        self.rot_lib = rot_lib

        self.subdialogs = {}
        from collections import OrderedDict
        self.opt_columns = OrderedDict()
        self.handlers = [
            self.mgr.triggers.add_handler('fewer rotamers',
                                          self._fewer_rots_cb),
            self.mgr.triggers.add_handler('self destroyed',
                                          self._mgr_destroyed_cb),
        ]
        from chimerax.ui.widgets import ItemTable
        global _settings
        if _settings is None:
            from chimerax.core.settings import Settings

            class _RotamerSettings(Settings):
                EXPLICIT_SAVE = {ItemTable.DEFAULT_SETTINGS_ATTR: {}}

            _settings = _RotamerSettings(self.session, "Rotamers")
        from chimerax.ui import MainToolWindow
        self.tool_window = tw = MainToolWindow(self)
        parent = tw.ui_area
        from PyQt5.QtWidgets import QVBoxLayout, QLabel, QCheckBox, QGroupBox, QWidget, QHBoxLayout, \
            QPushButton, QRadioButton, QButtonGroup, QGridLayout
        from PyQt5.QtCore import Qt
        self.layout = layout = QVBoxLayout()
        parent.setLayout(layout)
        lib_display_name = self.session.rotamers.library(rot_lib).display_name
        layout.addWidget(
            QLabel("%s %s rotamers" % (lib_display_name, res_type)))
        column_disp_widget = QWidget()

        class RotamerTable(ItemTable):
            def sizeHint(self):
                from PyQt5.QtCore import QSize
                return QSize(350, 450)

        self.table = RotamerTable(column_control_info=(column_disp_widget,
                                                       _settings, {}, True,
                                                       None, None, False),
                                  auto_multiline_headers=False)
        for i in range(len(self.mgr.rotamers[0].chis)):
            self.table.add_column("Chi %d" % (i + 1),
                                  lambda r, i=i: r.chis[i],
                                  format="%6.1f")
        self.table.add_column("Probability", "rotamer_prob", format="%.6f ")

        if table_info:
            table_state, additional_col_info = table_info
            for col_type, title, data_fetch, display_format in additional_col_info:
                AtomicStructure.register_attr(
                    self.session,
                    data_fetch,
                    self.registerer,
                    attr_type=(int if data_fetch.startswith("num") else float))
                self.opt_columns[col_type] = self.table.add_column(
                    title, data_fetch, format=display_format)
        else:
            table_state = None
        self.table.data = self.mgr.rotamers
        self.table.launch(session_info=table_state)
        if not table_info:
            self.table.sortByColumn(len(self.mgr.rotamers[0].chis),
                                    Qt.DescendingOrder)
        self.table.selection_changed.connect(self._selection_change)
        layout.addWidget(self.table)
        if mgr.base_residue.name == res_type:
            self.retain_side_chain = QCheckBox("Retain original side chain")
            self.retain_side_chain.setChecked(False)
            layout.addWidget(self.retain_side_chain)
        else:
            self.retain_side_chain = None

        column_group = QGroupBox("Column display")
        layout.addWidget(column_group)
        cg_layout = QVBoxLayout()
        cg_layout.setContentsMargins(0, 0, 0, 0)
        cg_layout.setSpacing(0)
        column_group.setLayout(cg_layout)
        cg_layout.addWidget(column_disp_widget)

        add_col_layout = QGridLayout()
        add_col_layout.setContentsMargins(0, 0, 0, 0)
        add_col_layout.setSpacing(0)
        cg_layout.addLayout(add_col_layout)
        self.add_col_button = QPushButton("Calculate")
        add_col_layout.addWidget(self.add_col_button,
                                 0,
                                 0,
                                 alignment=Qt.AlignRight)
        radio_layout = QVBoxLayout()
        radio_layout.setContentsMargins(0, 0, 0, 0)
        add_col_layout.addLayout(radio_layout, 0, 1, alignment=Qt.AlignLeft)
        self.button_group = QButtonGroup()
        self.add_col_button.clicked.connect(
            lambda checked, *, bg=self.button_group: self._show_subdialog(
                bg.checkedButton().text()))
        for add_type in ["H-Bonds", "Clashes", "Density"]:
            rb = QRadioButton(add_type)
            rb.clicked.connect(self._update_button_text)
            radio_layout.addWidget(rb)
            if not self.button_group.buttons():
                rb.setChecked(True)
            self.button_group.addButton(rb)
        self.ignore_solvent_button = QCheckBox("Ignore solvent")
        self.ignore_solvent_button.setChecked(True)
        add_col_layout.addWidget(self.ignore_solvent_button,
                                 1,
                                 0,
                                 1,
                                 2,
                                 alignment=Qt.AlignCenter)

        from PyQt5.QtWidgets import QDialogButtonBox as qbbox
        bbox = qbbox(qbbox.Ok | qbbox.Cancel | qbbox.Help)
        bbox.accepted.connect(self._apply_rotamer)
        bbox.rejected.connect(self.tool_window.destroy)
        from chimerax.core.commands import run
        bbox.helpRequested.connect(
            lambda run=run, ses=self.session: run(ses, "help " + self.help))
        layout.addWidget(bbox)
        self.tool_window.manage(placement=None)
Ejemplo n.º 9
0
    def __init__(self, session, tool_name):
        ToolInstance.__init__(self, session, tool_name)
        from chimerax.ui import MainToolWindow
        self.tool_window = tw = MainToolWindow(self)
        parent = tw.ui_area
        from PyQt5.QtWidgets import QVBoxLayout, QGridLayout, QLabel, QDialogButtonBox, QStackedWidget
        from PyQt5.QtWidgets import QCheckBox
        overall_layout = QVBoxLayout()
        overall_layout.setContentsMargins(0,0,0,0)
        overall_layout.setSpacing(0)
        parent.setLayout(overall_layout)

        matching_layout = QGridLayout()
        matching_layout.setContentsMargins(0,0,0,0)
        matching_layout.setSpacing(0)
        matching_layout.setColumnStretch(0, 1)
        matching_layout.setColumnStretch(1, 1)
        matching_layout.setRowStretch(1, 1)
        overall_layout.addLayout(matching_layout, stretch=1)
        self.label_texts = {
            CP_BEST_BEST: ("Reference structure:", "Structure(s) to match:"),
            CP_SPECIFIC_BEST: ("Reference chain:", "Structure(s) to match:"),
            CP_SPECIFIC_SPECIFIC: ("Reference chain(s):", "Chain(s) to match:")
        }
        self.ref_label = QLabel()
        matching_layout.addWidget(self.ref_label, 0, 0, alignment=Qt.AlignLeft)
        self.match_label = QLabel()
        matching_layout.addWidget(self.match_label, 0, 1, alignment=Qt.AlignLeft)
        self.ref_stacking = QStackedWidget()
        matching_layout.addWidget(self.ref_stacking, 1, 0)
        self.match_stacking = QStackedWidget()
        matching_layout.addWidget(self.match_stacking, 1, 1)
        from chimerax.atomic.widgets import AtomicStructureListWidget, ChainListWidget
        self.ref_structure_list = AtomicStructureListWidget(session, selection_mode='single')
        self.ref_stacking.addWidget(self.ref_structure_list)
        self.match_structure_structure_list = AtomicStructureListWidget(session,
            filter_func=lambda s, ref_list=self.ref_structure_list: s != ref_list.value)
        self.ref_structure_list.value_changed.connect(self.match_structure_structure_list.refresh)
        self.match_stacking.addWidget(self.match_structure_structure_list)
        self.ref_chain_list = ChainListWidget(session, selection_mode='single')
        self.ref_stacking.addWidget(self.ref_chain_list)
        self.match_chain_structure_list = AtomicStructureListWidget(session, filter_func=lambda s,
            ref_list=self.ref_chain_list: s != getattr(ref_list.value, 'structure', None))
        self.ref_chain_list.value_changed.connect(self.match_chain_structure_list.refresh)
        self.match_stacking.addWidget(self.match_chain_structure_list)
        self.ref_chains_list = ChainListWidget(session, autoselect='single')
        self.ref_stacking.addWidget(self.ref_chains_list)
        self.match_chain_lists = ChainListsWidget(session)
        self.ref_chains_list.value_changed.connect(
            lambda ref=self.ref_chains_list:self.match_chain_lists.update(ref.value))
        self.match_stacking.addWidget(self.match_chain_lists)
        self.matching_widgets = {
            CP_BEST_BEST: (self.ref_structure_list,  self.match_structure_structure_list),
            CP_SPECIFIC_BEST: (self.ref_chain_list, self.match_chain_structure_list),
            CP_SPECIFIC_SPECIFIC: (self.ref_chains_list, self.match_chain_lists),
        }
        self.ref_sel_restrict = QCheckBox("Also restrict to selection")
        matching_layout.addWidget(self.ref_sel_restrict, 2, 0, alignment=Qt.AlignCenter)
        self.match_sel_restrict = QCheckBox("Also restrict to selection")
        matching_layout.addWidget(self.match_sel_restrict, 2, 1, alignment=Qt.AlignCenter)

        from chimerax.ui.options import CategorizedSettingsPanel, IntOption, BooleanOption, FloatOption
        self.options = CategorizedSettingsPanel(category_sorting=False, option_sorting=False,
            category_scrolled={"Chain pairing": False})
        overall_layout.addWidget(self.options, stretch=1)
        from .settings import get_settings
        settings = get_settings(session)

        self.chain_pairing_option = cp_opt = ChainPairingOption("", None, self._pairing_change,
            attr_name="chain_pairing", settings=settings, as_radio_buttons=True)
        self.options.add_option("Chain pairing", cp_opt)

        from chimerax.alignment_algs.options import SeqAlignmentAlgOption
        self.options.add_option("Alignment", BooleanOption("Show pairwise sequence alignment(s)", None, None,
            attr_name="show_alignment", settings=settings))
        self.options.add_option("Alignment", SeqAlignmentAlgOption("Sequence alignment algorithm",
            None, None, attr_name="alignment_algorithm", settings=settings))
        from chimerax.sim_matrices.options import SimilarityMatrixNameOption
        self.options.add_option("Alignment", SimilarityMatrixNameOption("Matrix", None, None,
            attr_name="matrix", settings=settings))
        self.gap_open_option = IntOption("Gap opening penalty", None, None,
            attr_name="gap_open", settings=settings)
        self.options.add_option("Alignment", self.gap_open_option)
        self.options.add_option("Alignment", IntOption("Gap extension penalty", None, None,
            attr_name="gap_extend", settings=settings))
        ss_opt = BooleanOption("Include secondary structure score", None, self._include_ss_change,
            attr_name="use_ss", settings=settings)
        self.options.add_option("Alignment", ss_opt)
        self.ss_widget, ss_options = self.options.add_option_group("Alignment", sorting=False,
            group_label="Secondary structure scoring")
        ss_layout = QVBoxLayout()
        ss_layout.addWidget(ss_options)
        self.ss_widget.setLayout(ss_layout)
        self.compute_ss_option = BooleanOption("Compute secondary structure assignments", None,
            self._compute_ss_change, attr_name="compute_ss", settings=settings)
        ss_options.add_option(self.compute_ss_option)
        self.overwrite_ss_option = BooleanOption("Overwrite previous assignments", None, None,
            attr_name="overwrite_ss", settings=settings)
        ss_options.add_option(self.overwrite_ss_option)
        self.ss_ratio_option = FloatOption("Secondary structure weighting", None, None,
            attr_name="ss_mixture", settings=settings, as_slider=True, left_text="Residue similarity",
            right_text="Secondary structure", min=0.0, max=1.0, decimal_places=2, ignore_wheel_event=True)
        ss_options.add_option(self.ss_ratio_option)
        self.ss_matrix_option = SSScoringMatrixOption("Scoring matrix", None, None,
            attr_name='ss_scores', settings=settings)
        ss_options.add_option(self.ss_matrix_option)
        self.ss_helix_gap_option = IntOption("Intra-helix gap opening penalty", None, None,
            attr_name='helix_open', settings=settings)
        ss_options.add_option(self.ss_helix_gap_option)
        self.ss_strand_gap_option = IntOption("Intra-strand gap opening penalty", None, None,
            attr_name='strand_open', settings=settings)
        ss_options.add_option(self.ss_strand_gap_option)
        self.ss_other_gap_option = IntOption("Any other gap opening penalty", None, None,
            attr_name='other_open', settings=settings)
        ss_options.add_option(self.ss_other_gap_option)
        self._include_ss_change(ss_opt)

        iter_opt = BooleanOption("Iterate by pruning long atom pairs", None, self._iterate_change,
            attr_name="iterate", settings=settings)
        self.options.add_option("Fitting", iter_opt)
        self.iter_cutoff_option = FloatOption("Iteration cutoff distance", None, None,
            attr_name="iter_cutoff", settings=settings)
        self.options.add_option("Fitting", self.iter_cutoff_option)
        self._iterate_change(iter_opt)
        self.options.add_option("Fitting", BooleanOption("Verbose logging", None, None,
            attr_name="verbose_logging", settings=settings))
        bring_container, bring_options = self.options.add_option_group("Fitting",
            group_alignment=Qt.AlignHCenter|Qt.AlignTop)
        bring_layout = QVBoxLayout()
        bring_container.setLayout(bring_layout)
        self.bring_label = QLabel("If one model being matched, also move these models along with it:")
        bring_layout.addWidget(self.bring_label)
        from chimerax.ui.widgets import ModelListWidget
        self.bring_model_list = ModelListWidget(session, filter_func=self._filter_bring_models,
            autoselect=None)
        for ref_widget, match_widget in self.matching_widgets.values():
            ref_widget.value_changed.connect(self.bring_model_list.refresh)
            match_widget.value_changed.connect(self.bring_model_list.refresh)
            match_widget.value_changed.connect(self._match_value_change)
        bring_layout.addWidget(self.bring_model_list)
        self._match_value_change()

        from PyQt5.QtWidgets import QDialogButtonBox as qbbox
        bbox = qbbox(qbbox.Ok | qbbox.Apply | qbbox.Close | qbbox.Help)
        bbox.accepted.connect(self.run_matchmaker)
        bbox.button(qbbox.Apply).clicked.connect(self.run_matchmaker)
        bbox.accepted.connect(self.delete) # slots executed in the order they are connected
        bbox.rejected.connect(self.delete)
        from chimerax.core.commands import run
        bbox.helpRequested.connect(lambda run=run, ses=session: run(ses, "help " + self.help))
        overall_layout.addWidget(bbox)

        self._pairing_change(cp_opt)
        tw.manage(placement=None)
Ejemplo n.º 10
0
    def __init__(self, session, tool_name):
        ToolInstance.__init__(self, session, tool_name)

        from chimerax.ui import MainToolWindow
        self.tool_window = MainToolWindow(self,
                                          close_destroys=False,
                                          statusbar=False)
        parent = self.tool_window.ui_area

        from PyQt5.QtWidgets import QListWidget, QFormLayout, QAbstractItemView, QGroupBox, QVBoxLayout
        from PyQt5.QtWidgets import QDialogButtonBox as qbbox
        interface_layout = QVBoxLayout()
        interface_layout.setContentsMargins(0, 0, 0, 0)
        interface_layout.setSpacing(0)
        parent.setLayout(interface_layout)
        alignments_area = QGroupBox("Sequence alignments")
        interface_layout.addWidget(alignments_area)
        interface_layout.setStretchFactor(alignments_area, 1)
        alignments_layout = QVBoxLayout()
        alignments_layout.setContentsMargins(0, 0, 0, 0)
        alignments_area.setLayout(alignments_layout)
        self.alignment_list = AlignmentListWidget(session)
        self.alignment_list.setSelectionMode(
            QAbstractItemView.ExtendedSelection)
        self.alignment_list.keyPressEvent = session.ui.forward_keystroke
        self.alignment_list.value_changed.connect(self._list_selection_cb)
        self.alignment_list.alignments_changed.connect(
            self._update_sequence_menus)
        alignments_layout.addWidget(self.alignment_list)
        alignments_layout.setStretchFactor(self.alignment_list, 1)
        targets_area = QGroupBox("Target sequences")
        self.targets_layout = QFormLayout()
        targets_area.setLayout(self.targets_layout)
        interface_layout.addWidget(targets_area)
        self.seq_menu = {}
        self._update_sequence_menus(session.alignments.alignments)
        options_area = QGroupBox("Options")
        options_layout = QVBoxLayout()
        options_layout.setContentsMargins(0, 0, 0, 0)
        options_area.setLayout(options_layout)
        interface_layout.addWidget(options_area)
        interface_layout.setStretchFactor(options_area, 2)
        from chimerax.ui.options import CategorizedSettingsPanel, BooleanOption, IntOption, PasswordOption, \
            OutputFolderOption
        panel = CategorizedSettingsPanel(category_sorting=False, buttons=False)
        options_layout.addWidget(panel)
        from .settings import get_settings
        settings = get_settings(session)
        panel.add_option(
            "Basic",
            BooleanOption(
                "Make multichain model from multichain template",
                settings.multichain,
                None,
                balloon=
                "If false, all chains (templates) associated with an alignment will be used in combination\n"
                "to model the target sequence of that alignment, i.e. a monomer will be generated from the\n"
                "alignment.  If true, the target sequence will be modeled from each template, i.e. a multimer\n"
                "will be generated from the alignment (assuming multiple chains are associated).",
                attr_name="multichain",
                settings=settings))
        max_models = 1000
        panel.add_option(
            "Basic",
            IntOption(
                "Number of models",
                settings.num_models,
                None,
                attr_name="num_models",
                settings=settings,
                min=1,
                max=max_models,
                balloon=
                "Number of model structures to generate.  Must be no more than %d.\n"
                "Warning: please consider the calculation time" % max_models))
        key = "" if settings.license_key is None else settings.license_key
        panel.add_option(
            "Basic",
            PasswordOption(
                "Modeller license key",
                key,
                None,
                attr_name="license_key",
                settings=settings,
                balloon=
                "Your Modeller license key.  You can obtain a license key by registering at the Modeller web site"
            ))
        panel.add_option(
            "Advanced",
            BooleanOption(
                "Use fast/approximate mode (produces only one model)",
                settings.fast,
                None,
                attr_name="fast",
                settings=settings,
                balloon=
                "If enabled, use a fast approximate method to generate a single model.\n"
                "Typically use to get a rough idea what the model will look like or\n"
                "to check that the alignment is reasonable."))
        panel.add_option(
            "Advanced",
            BooleanOption(
                "Include non-water HETATM residues from template",
                settings.het_preserve,
                None,
                attr_name="het_preserve",
                settings=settings,
                balloon=
                "If enabled, all non-water HETATM residues in the template\n"
                "structure(s) will be transferred into the generated models."))
        panel.add_option(
            "Advanced",
            BooleanOption(
                "Build models with hydrogens",
                settings.hydrogens,
                None,
                attr_name="hydrogens",
                settings=settings,
                balloon=
                "If enabled, the generated models will include hydrogen atoms.\n"
                "Otherwise, only heavy atom coordinates will be built.\n"
                "Increases computation time by approximately a factor of 4."))
        panel.add_option(
            "Advanced",
            OutputFolderOption(
                "Temporary folder location (optional)",
                settings.temp_path,
                None,
                attr_name="temp_path",
                settings=settings,
                balloon=
                "Specify a folder for temporary files.  If not specified,\n"
                "a location will be generated automatically."))
        panel.add_option(
            "Advanced",
            BooleanOption(
                "Include water molecules from template",
                settings.water_preserve,
                None,
                attr_name="water_preserve",
                settings=settings,
                balloon="If enabled, all water molecules in the template\n"
                "structure(s) will be included in the generated models."))
        from PyQt5.QtCore import Qt
        from chimerax.ui.widgets import Citation
        interface_layout.addWidget(Citation(
            session, "A. Sali and T.L. Blundell.\n"
            "Comparative protein modelling by satisfaction of spatial restraints.\n"
            "J. Mol. Biol. 234, 779-815, 1993.",
            prefix="Publications using Modeller results should cite:",
            pubmed_id=18428767),
                                   alignment=Qt.AlignCenter)
        bbox = qbbox(qbbox.Ok | qbbox.Cancel | qbbox.Help)
        bbox.accepted.connect(self.launch_modeller)
        bbox.rejected.connect(self.delete)
        from chimerax.core.commands import run
        bbox.helpRequested.connect(
            lambda run=run, ses=session: run(ses, "help " + self.help))
        interface_layout.addWidget(bbox)
        self.tool_window.manage(None)
Ejemplo n.º 11
0
    def __init__(self, *args, **kw):
        super().__init__(*args, **kw)

        from chimerax.ui import MainToolWindow
        self.tool_window = tw = MainToolWindow(self, close_destroys=False)
        parent = tw.ui_area

        from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QDialogButtonBox, QWidget, QPushButton, \
            QLabel, QCheckBox, QFrame, QGroupBox, QGridLayout, QScrollArea
        from PyQt5.QtGui import QColor, QPixmap, QIcon
        from PyQt5.QtCore import Qt, QTimer
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        parent.setLayout(layout)

        main_dialog_area = QWidget()
        layout.addWidget(main_dialog_area)
        main_layout = QHBoxLayout()
        main_layout.setContentsMargins(0, 7, 0, 7)
        main_dialog_area.setLayout(main_layout)

        fav_color_area = QWidget()
        main_layout.addWidget(fav_color_area)
        fav_color_layout = QVBoxLayout()
        fav_color_layout.setContentsMargins(0, 0, 0, 0)
        fav_color_layout.setSpacing(0)
        fav_color_area.setLayout(fav_color_layout)
        spaced_names = [
            "red", "orange red", "orange", "yellow", "lime", "forest green",
            "cyan", "light sea green", "blue", "cornflower blue",
            "medium blue", "purple", "hot pink", "magenta", "white",
            "light gray", "gray", "dark gray", "dim gray", "black"
        ]
        for spaced_name in spaced_names:
            svg_name = "".join(spaced_name.split())
            color = QColor(svg_name)
            pixmap = QPixmap(16, 16)
            pixmap.fill(color)
            icon = QIcon(pixmap)
            button = QPushButton(icon, spaced_name.title())
            button.released.connect(lambda clr=spaced_name: self._color(clr))
            button.setStyleSheet("QPushButton { text-align: left; }")
            fav_color_layout.addWidget(button)

        actions_area = QWidget()
        main_layout.addWidget(actions_area)
        actions_layout = QVBoxLayout()
        actions_area.setLayout(actions_layout)

        actions_layout.addStretch(1)

        header = QLabel("Coloring applies to:")
        header.setWordWrap(True)
        header.setAlignment(Qt.AlignCenter)
        actions_layout.addWidget(header,
                                 alignment=Qt.AlignBottom | Qt.AlignHCenter)
        self.target_button_info = []
        for label, target, initial_on in [("Atoms/Bonds", 'a', True),
                                          ("Cartoons", 'c', True),
                                          ("Surfaces", 's', True),
                                          ("Pseudobonds", 'p', True),
                                          ("Ring Fill", 'f', True),
                                          ("Labels", 'l', False)]:
            chk = QCheckBox(label)
            chk.setChecked(initial_on)
            chk.clicked.connect(self._clear_global_buttons)
            actions_layout.addWidget(chk)
            self.target_button_info.append((chk, target))

        sep = QFrame()
        sep.setFrameStyle(QFrame.HLine)
        actions_layout.addWidget(sep, stretch=1)

        self.global_button_info = []
        for label, command in [("Background", "set bg %s")]:
            chk = QCheckBox(label)
            chk.setChecked(False)
            chk.clicked.connect(self._clear_targeted_buttons)
            actions_layout.addWidget(chk)
            self.global_button_info.append((chk, command))

        actions_layout.addStretch(1)

        from chimerax.core.commands import run
        grp = QGroupBox("Other colorings:")
        actions_layout.addWidget(grp)
        grp_layout = QVBoxLayout()
        grp_layout.setContentsMargins(0, 0, 0, 0)
        grp_layout.setSpacing(0)
        grp.setLayout(grp_layout)
        for label, arg, tooltip in [
            ("Heteroatom", "het",
             "Color non-carbon atoms by chemical element"),
            ("Element", "element", "Color atoms by chemical element"),
            ("Nucleotide Type", "nucleotide",
             "Color nucleotide residues by the type of their base"),
            ("Chain", "chain", "Give each chain a different color"),
            ("Polymer", "polymer",
             "Color chains differently, except that chains with the same sequence"
             " receive the same color")
        ]:
            but = QPushButton("By " + label)
            if tooltip:
                but.setToolTip(tooltip)
            but.clicked.connect(
                lambda *, run=run, ses=self.session, arg=arg: run(
                    ses, "color " +
                    ("" if ses.selection.empty() else "sel ") + "by" + arg))
            grp_layout.addWidget(but)
        but = QPushButton("From Editor")
        but.setToolTip("Bring up a color editor to choose the color")
        but.clicked.connect(self.session.ui.main_window.color_by_editor)
        grp_layout.addWidget(but)

        actions_layout.addStretch(1)

        self.all_colors_check_box = chk = QCheckBox(
            "Show all colors \N{RIGHTWARDS ARROW}")
        chk.setChecked(False)
        chk.clicked.connect(self._toggle_all_colors)
        actions_layout.addWidget(chk, alignment=Qt.AlignRight)

        actions_layout.addStretch(1)

        self.all_colors_area = QScrollArea()
        # hack to get reasonable initial size; allow smaller resize after show()
        self.ac_preferred_width = 500
        self.all_colors_area.setHidden(True)
        all_colors_widget = QWidget()
        from chimerax.core.colors import BuiltinColors
        # for colors with the exact same RGBA value, only keep one
        canonical = {}
        for name, color in BuiltinColors.items():
            key = tuple(color.rgba)
            if key[-1] == 0.0:
                continue
            try:
                canonical_name = canonical[key]
            except KeyError:
                canonical[key] = name
                continue
            if 'grey' in name:
                continue
            if 'grey' in canonical_name:
                canonical[key] = name
                continue
            if len(name) > len(canonical_name):
                # names with spaces in them are longer...
                canonical[key] = name
                continue
            if len(name) == len(canonical_name) and name > canonical_name:
                # tie breaker for otherwise equal-value names, so that
                # the set of names is the same between invocations of the tool
                canonical[key] = name
        rgbas = list(canonical.keys())
        rgbas.sort(key=self._rgba_key)
        color_names = [canonical[rgba] for rgba in rgbas]
        all_colors_layout = QGridLayout()
        all_colors_layout.setContentsMargins(0, 0, 0, 0)
        all_colors_layout.setSpacing(0)
        all_colors_widget.setLayout(all_colors_layout)
        num_rows = len(spaced_names)
        row = column = 0
        for spaced_name in color_names:
            #svg_name = "".join(spaced_name.split())
            #color = QColor(svg_name)
            # QColor doesn't know the name "rebeccapurple", so...
            color = QColor(
                *[int(c * 255 + 0.5) for c in BuiltinColors[spaced_name].rgba])
            pixmap = QPixmap(16, 16)
            pixmap.fill(color)
            icon = QIcon(pixmap)
            button = QPushButton(icon, spaced_name.title())
            button.released.connect(lambda clr=spaced_name: self._color(clr))
            button.setStyleSheet("QPushButton { text-align: left; }")
            all_colors_layout.addWidget(button, row, column)
            row += 1
            if row >= num_rows:
                row = 0
                column += 1
        self.all_colors_area.setWidget(all_colors_widget)
        main_layout.addWidget(self.all_colors_area)

        from PyQt5.QtWidgets import QDialogButtonBox as qbbox
        bbox = qbbox(qbbox.Close | qbbox.Help)
        bbox.rejected.connect(self.delete)
        if self.help:
            bbox.helpRequested.connect(lambda run=run, ses=self.session: run(
                ses, "help " + self.help))
        else:
            bbox.button(qbbox.Help).setEnabled(False)
        layout.addWidget(bbox)

        tw.manage(placement=None)