Beispiel #1
0
    def __init__(self, parent=None):
        super().__init__(parent)

        loader = UiLoader()
        self.ui = loader.load_file('materials_panel.ui', parent)

        m = HexrdConfig().active_material
        self.material_editor_widget = MaterialEditorWidget(m, self.ui)
        self.reflections_table = ReflectionsTable(m, parent=self.ui)

        self.ui.material_editor_layout.addWidget(
            self.material_editor_widget.ui)

        self.material_structure_editor = MaterialStructureEditor(self.ui)
        self.ui.material_structure_editor_layout.addWidget(
            self.material_structure_editor.ui)

        self.material_properties_editor = MaterialPropertiesEditor(self.ui)
        self.ui.material_properties_editor_layout.addWidget(
            self.material_properties_editor.ui)

        # Turn off autocomplete for the QComboBox
        self.ui.materials_combo.setCompleter(None)

        self.add_tool_button_actions()

        self.setup_connections()

        self.update_gui_from_config()
Beispiel #2
0
 def choose_hkls(self):
     kwargs = {
         'material': self.material,
         'title_prefix': 'Select hkls for grain fitting: ',
         'parent': self.ui,
     }
     self._table = ReflectionsTable(**kwargs)
     self._table.show()
Beispiel #3
0
 def choose_hkls(self):
     kwargs = {
         'material': self.material,
         'title_prefix': 'Select hkls for eta omega map generation: ',
         'parent': self.ui,
     }
     self._table = ReflectionsTable(**kwargs)
     self._table.show()
Beispiel #4
0
    def show_reflections_table(self):
        if not hasattr(self, '_table'):
            kwargs = {
                'material': self.material,
                'parent': self.ui,
            }
            self._table = ReflectionsTable(**kwargs)
        else:
            # Make sure the material is up to date
            self._table.material = self.material

        self._table.show()
Beispiel #5
0
class MaterialsPanel(QObject):
    def __init__(self, parent=None):
        super().__init__(parent)

        loader = UiLoader()
        self.ui = loader.load_file('materials_panel.ui', parent)

        m = HexrdConfig().active_material
        self.material_editor_widget = MaterialEditorWidget(m, self.ui)
        self.reflections_table = ReflectionsTable(m, parent=self.ui)

        self.ui.material_editor_layout.addWidget(
            self.material_editor_widget.ui)

        self.material_structure_editor = MaterialStructureEditor(self.ui)
        self.ui.material_structure_editor_layout.addWidget(
            self.material_structure_editor.ui)

        self.material_properties_editor = MaterialPropertiesEditor(self.ui)
        self.ui.material_properties_editor_layout.addWidget(
            self.material_properties_editor.ui)

        # Turn off autocomplete for the QComboBox
        self.ui.materials_combo.setCompleter(None)

        self.add_tool_button_actions()

        self.setup_connections()

        self.update_gui_from_config()

    def add_tool_button_actions(self):
        b = self.ui.materials_tool_button

        m = QMenu(b)
        self.tool_button_menu = m

        self.add_material_action = m.addAction('Add material')
        self.import_material_action = m.addAction('Import material')
        self.delete_material_action = m.addAction('Delete material')

        b.setMenu(m)

    def setup_connections(self):
        self.ui.materials_combo.installEventFilter(self)
        self.add_material_action.triggered.connect(self.add_material)
        self.import_material_action.triggered.connect(self.import_material)
        self.delete_material_action.triggered.connect(
            self.remove_current_material)
        self.ui.materials_combo.currentIndexChanged.connect(
            self.set_active_material)
        self.ui.materials_combo.currentIndexChanged.connect(
            self.update_enable_states)
        self.ui.materials_combo.currentIndexChanged.connect(self.update_table)
        self.ui.materials_combo.lineEdit().editingFinished.connect(
            self.modify_material_name)

        self.material_editor_widget.material_modified.connect(
            self.material_edited)

        self.ui.show_reflections_table.pressed.connect(
            self.show_reflections_table)
        self.ui.show_overlay_manager.pressed.connect(self.show_overlay_manager)

        self.ui.show_overlays.toggled.connect(HexrdConfig()._set_show_overlays)

        self.ui.limit_active.toggled.connect(
            HexrdConfig().set_limit_active_rings)
        self.ui.max_tth.valueChanged.connect(self.on_max_tth_changed)
        self.ui.min_d_spacing.valueChanged.connect(
            self.on_min_d_spacing_changed)

        HexrdConfig().new_plane_data.connect(self.update_gui_from_config)

        self.ui.limit_active.toggled.connect(self.update_enable_states)
        self.ui.limit_active.toggled.connect(self.update_material_limits)
        self.ui.limit_active.toggled.connect(self.update_table)

        HexrdConfig().active_material_changed.connect(
            self.active_material_changed)
        HexrdConfig().active_material_modified.connect(
            self.active_material_modified)

        self.material_structure_editor.material_modified.connect(
            self.material_structure_edited)

    def update_enable_states(self):
        limit_active = self.ui.limit_active.isChecked()
        self.ui.max_tth.setEnabled(limit_active)
        self.ui.min_d_spacing.setEnabled(limit_active)
        self.ui.min_d_spacing_label.setEnabled(limit_active)
        self.ui.max_tth_label.setEnabled(limit_active)

    def on_max_tth_changed(self):
        max_tth = math.radians(self.ui.max_tth.value())
        wavelength = HexrdConfig().beam_wavelength

        w = self.ui.min_d_spacing
        block_signals = w.blockSignals(True)
        try:
            # Bragg's law
            max_bragg = max_tth / 2.0
            d = wavelength / (2.0 * math.sin(max_bragg))
            w.setValue(d)
        finally:
            w.blockSignals(block_signals)

        # Update the config
        HexrdConfig().active_material_tth_max = max_tth
        self.update_table()

    def on_min_d_spacing_changed(self):
        min_d = self.ui.min_d_spacing.value()
        wavelength = HexrdConfig().beam_wavelength

        w = self.ui.max_tth
        block_signals = w.blockSignals(True)
        try:
            # Bragg's law
            theta = math.degrees(math.asin(wavelength / 2.0 / min_d))
            w.setValue(theta * 2.0)
        finally:
            w.blockSignals(block_signals)

        # Update the config
        HexrdConfig().active_material_tth_max = math.radians(theta * 2.0)
        self.update_table()

    def update_gui_from_config(self):
        block_list = [
            self.material_editor_widget, self.ui.materials_combo,
            self.ui.show_overlays, self.ui.min_d_spacing, self.ui.max_tth,
            self.ui.limit_active
        ]
        blockers = [QSignalBlocker(x) for x in block_list]

        combo = self.ui.materials_combo
        current_items = [combo.itemText(x) for x in range(combo.count())]
        materials_keys = list(HexrdConfig().materials.keys())

        # If the materials in the config have changed, re-build the list
        if current_items != materials_keys:
            self.ui.materials_combo.clear()
            self.ui.materials_combo.addItems(materials_keys)

        self.material_editor_widget.material = HexrdConfig().active_material
        self.ui.materials_combo.setCurrentIndex(
            materials_keys.index(HexrdConfig().active_material_name))
        self.ui.show_overlays.setChecked(HexrdConfig().show_overlays)

        self.ui.limit_active.setChecked(HexrdConfig().limit_active_rings)

        # Unblock the signal blockers before proceeding
        del blockers

        self.update_material_limits()
        self.update_table()
        self.update_enable_states()

    def active_material_modified(self):
        self.update_gui_from_config()
        self.material_editor_widget.update_gui_from_material()
        self.update_structure_tab()
        self.update_properties_tab()

    def material_edited(self):
        self.update_table()
        self.update_refinement_options()
        self.update_properties_tab()

    def material_structure_edited(self):
        self.update_table()
        self.update_properties_tab()

    def update_structure_tab(self):
        self.material_structure_editor.update_gui()

    def update_properties_tab(self):
        self.material_properties_editor.update_gui()

    def update_material_limits(self):
        max_tth = HexrdConfig().active_material_tth_max
        if max_tth is None:
            # Display the backup if it is None
            max_tth = HexrdConfig().backup_tth_max

        max_bragg = max_tth / 2.0

        # Bragg's law
        min_d_spacing = HexrdConfig().beam_wavelength / (2.0 *
                                                         math.sin(max_bragg))

        block_list = [self.ui.min_d_spacing, self.ui.max_tth]
        block_signals = [item.blockSignals(True) for item in block_list]
        try:
            self.ui.max_tth.setValue(math.degrees(max_tth))
            self.ui.min_d_spacing.setValue(min_d_spacing)
        finally:
            for b, item in zip(block_signals, block_list):
                item.blockSignals(b)

    def set_active_material(self):
        HexrdConfig().active_material = self.current_material()

    def active_material_changed(self):
        self.reflections_table.material = HexrdConfig().active_material
        self.update_gui_from_config()
        self.update_structure_tab()
        self.update_properties_tab()

    def current_material(self):
        return self.ui.materials_combo.currentText()

    def add_material(self):
        # Create a default material
        new_mat = Material()

        # Get a unique name
        base_name = 'new_material'
        names = list(HexrdConfig().materials.keys())
        for i in range(1, 100000):
            new_name = f'{base_name}_{i}'
            if new_name not in names:
                new_mat.name = new_name
                break

        HexrdConfig().add_material(new_name, new_mat)
        HexrdConfig().active_material = new_name

    def import_material(self):
        selected_file, selected_filter = QFileDialog.getOpenFileName(
            self.ui, 'Import Material',
            HexrdConfig().working_dir, 'CIF files (*.cif)')

        if selected_file:
            HexrdConfig().working_dir = os.path.dirname(selected_file)
            new_name = HexrdConfig().import_material(selected_file)
            HexrdConfig().active_material = new_name

    def remove_current_material(self):
        # Don't allow the user to remove all of the materials
        if len(HexrdConfig().materials.keys()) == 1:
            msg = 'Cannot remove all materials. Add another first.'
            QMessageBox.warning(self.ui, 'HEXRD', msg)
            return

        name = self.current_material()
        HexrdConfig().remove_material(name)

    def modify_material_name(self):
        combo = self.ui.materials_combo

        new_name = combo.currentText()
        names = HexrdConfig().materials.keys()

        if new_name in names:
            # Just ignore it
            return

        old_name = HexrdConfig().active_material_name
        HexrdConfig().rename_material(old_name, new_name)

        # Update the text of the combo box item in the list
        combo.setItemText(combo.currentIndex(), new_name)

    def show_reflections_table(self):
        self.reflections_table.show()

    def show_overlay_manager(self):
        if hasattr(self, '_overlay_manager'):
            self._overlay_manager.ui.reject()
            del self._overlay_manager

        self._overlay_manager = OverlayManager(self.ui)
        self._overlay_manager.show()

    def update_table(self):
        HexrdConfig().update_reflections_tables.emit(self.current_material())

    def update_overlay_editor(self):
        if not hasattr(self, '_overlay_manager'):
            return

        self._overlay_manager.update_overlay_editor()

    def update_refinement_options(self):
        if not hasattr(self, '_overlay_manager'):
            return

        self._overlay_manager.update_refinement_options()

    def eventFilter(self, target, event):
        # This is almost identical to CalibrationConfigWidget.eventFilter
        # The logic is explained there.
        # We should keep this and CalibrationConfigWidget.eventFilter similar.
        if type(target) == QComboBox:
            if target.objectName() == 'materials_combo':
                enter_keys = [Qt.Key_Return, Qt.Key_Enter]
                if type(event) == QKeyEvent and event.key() in enter_keys:
                    widget = self.ui.materials_combo
                    widget.lineEdit().clearFocus()
                    return True

                if type(event) == QFocusEvent and event.lostFocus():
                    # This happens either if enter is pressed, or if the
                    # user tabs out.
                    widget = self.ui.materials_combo
                    items = [widget.itemText(i) for i in range(widget.count())]
                    text = widget.currentText()
                    idx = widget.currentIndex()
                    if text in items and widget.itemText(idx) != text:
                        # Prevent the QComboBox from automatically changing
                        # the index to be that of the other item in the list.
                        # This is confusing behavior, and it's not what we
                        # want here.
                        widget.setCurrentIndex(idx)
                        # Let the widget lose focus
                        return False

        return False
Beispiel #6
0
class PowderOverlayEditor:
    def __init__(self, parent=None):
        loader = UiLoader()
        self.ui = loader.load_file('powder_overlay_editor.ui', parent)

        self._overlay = None

        refinements = copy.deepcopy(DEFAULT_POWDER_REFINEMENTS)
        self.refinements_selector = SelectItemsWidget(refinements, self.ui)
        self.ui.refinements_selector_layout.addWidget(
            self.refinements_selector.ui)

        self.update_refinement_options()

        self.setup_connections()

    def setup_connections(self):
        for w in self.widgets:
            if isinstance(w, QDoubleSpinBox):
                w.valueChanged.connect(self.update_config)
            elif isinstance(w, QCheckBox):
                w.toggled.connect(self.update_config)

        self.ui.enable_width.toggled.connect(self.update_enable_states)
        self.refinements_selector.selection_changed.connect(
            self.update_refinements)

        self.ui.reflections_table.pressed.connect(self.show_reflections_table)

        HexrdConfig().material_tth_width_modified.connect(
            self.material_tth_width_modified_externally)

    def update_refinement_options(self):
        if self.overlay is None:
            return

        default_refinements = copy.deepcopy(DEFAULT_POWDER_REFINEMENTS)
        indices = unitcell._rqpDict[self.material.unitcell.latticeType][0]

        # Save the previous values
        prev_refinements = copy.deepcopy(self.refinements_selector.items)

        def get_prev_val(name, default=True):
            for entry in prev_refinements:
                if entry[0] == name:
                    return entry[1]

            return default

        refinements = []
        for i in indices:
            name, val = default_refinements[i]
            refinements.append((name, get_prev_val(name, default=val)))

        self.refinements_selector.items = refinements
        self.update_refinements()

    @property
    def refinements(self):
        return self.refinements_selector.items

    @refinements.setter
    def refinements(self, v):
        self.refinements_selector.items = copy.deepcopy(v)
        self.refinements_selector.update_table()

    def update_refinements(self):
        self.overlay['refinements'] = copy.deepcopy(self.refinements)

    @property
    def overlay(self):
        return self._overlay

    @overlay.setter
    def overlay(self, v):
        self._overlay = v
        self.update_gui()

    def update_enable_states(self):
        enable_width = self.ui.enable_width.isChecked()
        self.ui.tth_width.setEnabled(enable_width)

    def update_gui(self):
        if self.overlay is None:
            return

        blockers = [QSignalBlocker(w) for w in self.widgets]  # noqa: F841

        self.tth_width_gui = self.tth_width_config
        self.offset_gui = self.offset_config

        if 'refinements' in self.overlay:
            self.refinements = self.overlay['refinements']
        else:
            self.refinements = DEFAULT_POWDER_REFINEMENTS

        self.update_enable_states()
        self.update_refinement_options()
        self.update_reflections_table()

    def update_config(self):
        self.tth_width_config = self.tth_width_gui
        self.offset_config = self.offset_gui

        self.overlay['update_needed'] = True
        HexrdConfig().overlay_config_changed.emit()

    @property
    def material(self):
        if self.overlay is None:
            return None

        name = self.overlay['material']
        return HexrdConfig().material(name)

    @property
    def tth_width_config(self):
        if self.overlay is None:
            return None

        return self.material.planeData.tThWidth

    @tth_width_config.setter
    def tth_width_config(self, v):
        if self.overlay is None:
            return

        self.material.planeData.tThWidth = v

        # All overlays that use this material will be affected
        HexrdConfig().flag_overlay_updates_for_material(self.material.name)

    @property
    def tth_width_gui(self):
        if not self.ui.enable_width.isChecked():
            return None
        return np.radians(self.ui.tth_width.value())

    @tth_width_gui.setter
    def tth_width_gui(self, v):
        enable_width = v is not None
        self.ui.enable_width.setChecked(enable_width)
        if enable_width:
            self.ui.tth_width.setValue(np.degrees(v))

    @property
    def offset_config(self):
        if self.overlay is None:
            return

        options = self.overlay.get('options', {})
        if 'tvec' not in options:
            return

        return options['tvec']

    @offset_config.setter
    def offset_config(self, v):
        if self.overlay is None:
            return

        self.overlay['options']['tvec'] = v

    @property
    def offset_gui(self):
        return [w.value() for w in self.offset_widgets]

    @offset_gui.setter
    def offset_gui(self, v):
        if v is None:
            return

        for i, w in enumerate(self.offset_widgets):
            w.setValue(v[i])

    @property
    def offset_widgets(self):
        return [getattr(self.ui, f'offset_{i}') for i in range(3)]

    @property
    def widgets(self):
        return [self.ui.enable_width, self.ui.tth_width] + self.offset_widgets

    def material_tth_width_modified_externally(self, material_name):
        if material_name != self.material.name:
            return

        self.update_gui()

    def update_reflections_table(self):
        if hasattr(self, '_table'):
            self._table.material = self.material

    def show_reflections_table(self):
        if not hasattr(self, '_table'):
            kwargs = {
                'material': self.material,
                'parent': self.ui,
            }
            self._table = ReflectionsTable(**kwargs)
        else:
            # Make sure the material is up to date
            self._table.material = self.material

        self._table.show()
Beispiel #7
0
class FitGrainsOptionsDialog(QObject):
    accepted = Signal()
    rejected = Signal()

    def __init__(self, parent=None):
        super().__init__(parent)

        config = HexrdConfig().indexing_config['fit_grains']
        if config.get('do_fit') is False:
            return

        loader = UiLoader()
        self.ui = loader.load_file('fit_grains_options_dialog.ui', parent)
        flags = self.ui.windowFlags()
        self.ui.setWindowFlags(flags | Qt.Tool)

        self.setup_material_options()

        ok_button = self.ui.button_box.button(QDialogButtonBox.Ok)
        ok_button.setText('Fit Grains')

        self.tolerances_model = FitGrainsToleranceModel(self.ui)
        self.update_gui_from_config(config)
        self.ui.tolerances_view.setModel(self.tolerances_model)

        # Stretch columns to fill the available horizontal space
        num_cols = self.tolerances_model.columnCount()
        for i in range(num_cols):
            self.ui.tolerances_view.horizontalHeader().setSectionResizeMode(
                i, QHeaderView.Stretch)

        # Setup connections
        self.ui.accepted.connect(self.on_accepted)
        self.ui.rejected.connect(self.rejected)
        self.ui.tth_max_enable.toggled.connect(self.on_tth_max_toggled)
        self.ui.tth_max_specify.toggled.connect(self.on_tth_specify_toggled)
        self.ui.tolerances_view.selectionModel().selectionChanged.connect(
            self.on_tolerances_select)
        self.ui.add_row.clicked.connect(self.on_tolerances_add_row)
        self.ui.delete_row.clicked.connect(self.on_tolerances_delete_row)
        self.ui.move_up.clicked.connect(self.on_tolerances_move_up)
        self.ui.move_down.clicked.connect(self.on_tolerances_move_down)

        self.ui.material.currentIndexChanged.connect(
            self.selected_material_changed)
        self.ui.choose_hkls.pressed.connect(self.choose_hkls)

        self.ui.set_spots_directory.clicked.connect(self.set_working_dir)

        HexrdConfig().overlay_config_changed.connect(self.update_num_hkls)

    def all_widgets(self):
        """Only includes widgets directly related to config parameters"""
        widgets = [
            self.ui.npdiv,
            self.ui.refit_ome_step_scale,
            self.ui.refit_pixel_scale,
            self.ui.tolerances_view,
            self.ui.threshold,
            self.ui.tth_max_enable,
            self.ui.tth_max_instrument,
            self.ui.tth_max_specify,
            self.ui.tth_max_value,
        ]
        return widgets

    def show(self):
        self.ui.show()

    def setup_material_options(self):
        self.ui.material.clear()
        self.ui.material.addItems(list(HexrdConfig().materials.keys()))
        self.ui.material.setCurrentText(HexrdConfig().active_material_name)

    def on_accepted(self):
        # Save the selected options on the config
        self.update_config()
        self.accepted.emit()

    def on_tolerances_add_row(self):
        new_row_num = self.tolerances_model.rowCount()
        self.tolerances_model.add_row()

        # Select first column of new row
        self.ui.tolerances_view.setFocus(Qt.OtherFocusReason)
        self.ui.tolerances_view.selectionModel().clear()
        model_index = self.tolerances_model.index(new_row_num, 0)
        self.ui.tolerances_view.selectionModel().setCurrentIndex(
            model_index, QItemSelectionModel.Select)
        # Have to repaint - is that because we are in a modal dialog?
        self.ui.tolerances_view.repaint(self.ui.tolerances_view.rect())

    def on_tolerances_delete_row(self):
        rows = self._get_selected_rows()
        self.tolerances_model.delete_rows(rows)
        self.ui.tolerances_view.selectionModel().clear()
        self.ui.tolerances_view.repaint(self.ui.tolerances_view.rect())

    def on_tolerances_move_down(self):
        rows = self._get_selected_rows()
        self.tolerances_model.move_rows(rows, 1)
        self.ui.tolerances_view.selectionModel().clear()
        self.ui.tolerances_view.repaint(self.ui.tolerances_view.rect())

    def on_tolerances_move_up(self):
        rows = self._get_selected_rows()
        self.tolerances_model.move_rows(rows, -1)
        self.ui.tolerances_view.selectionModel().clear()
        self.ui.tolerances_view.repaint(self.ui.tolerances_view.rect())

    def on_tolerances_select(self):
        """Sets button enable states based on current selection"""
        delete_enable = False
        up_enable = False
        down_enable = False

        # Get list of selected rows
        selected_rows = self._get_selected_rows()
        if selected_rows:
            # Enable delete if more than 1 row
            num_rows = self.tolerances_model.rowCount()
            delete_enable = num_rows > 1

            # Are selected rows contiguous?
            num_selected = len(selected_rows)
            span = selected_rows[-1] - selected_rows[0] + 1
            is_contiguous = num_selected == span
            if is_contiguous:
                up_enable = selected_rows[0] > 0
                last_row = self.tolerances_model.rowCount() - 1
                down_enable = selected_rows[-1] < last_row

        self.ui.delete_row.setEnabled(delete_enable)
        self.ui.move_up.setEnabled(up_enable)
        self.ui.move_down.setEnabled(down_enable)

    def on_tth_max_toggled(self, checked):
        enabled = checked
        self.ui.tth_max_instrument.setEnabled(enabled)
        self.ui.tth_max_specify.setEnabled(enabled)
        specify = self.ui.tth_max_specify.isChecked()
        self.ui.tth_max_value.setEnabled(enabled and specify)

    def on_tth_specify_toggled(self, checked):
        self.ui.tth_max_value.setEnabled(checked)

    def update_config(self):
        # Set the new config options on the internal config
        config = HexrdConfig().indexing_config['fit_grains']
        config['npdiv'] = self.ui.npdiv.value()
        config['refit'][0] = self.ui.refit_pixel_scale.value()
        config['refit'][1] = self.ui.refit_ome_step_scale.value()
        config['threshold'] = self.ui.threshold.value()
        if not self.ui.tth_max_enable.isChecked():
            config['tth_max'] = False
        elif self.ui.tth_max_instrument.isChecked():
            config['tth_max'] = True
        else:
            config['tth_max'] = self.ui.tth_max_value.value()

        self.tolerances_model.copy_to_config(config)

        indexing_config = HexrdConfig().indexing_config
        indexing_config['analysis_name'] = Path(self.spots_path).stem
        indexing_config['working_dir'] = str(Path(self.spots_path).parent)
        indexing_config['_selected_material'] = self.selected_material
        indexing_config['_write_spots'] = self.ui.write_out_spots.isChecked()

    def update_gui_from_config(self, config):
        blocked = [QSignalBlocker(x) for x in self.all_widgets()]
        self.ui.npdiv.setValue(config.get('npdiv'))
        self.ui.refit_pixel_scale.setValue(config.get('refit')[0])
        self.ui.refit_ome_step_scale.setValue(config.get('refit')[1])
        self.ui.threshold.setValue(config.get('threshold'))

        tth_max = config.get('tth_max')
        if isinstance(tth_max, bool):
            enabled = tth_max
            instrument = tth_max
            value = 0.0
        else:
            enabled = True
            instrument = False
            value = tth_max

        self.ui.tth_max_enable.setChecked(enabled)

        self.ui.tth_max_instrument.setEnabled(enabled)
        self.ui.tth_max_instrument.setChecked(instrument)

        self.ui.tth_max_specify.setEnabled(enabled)
        self.ui.tth_max_specify.setChecked(not instrument)

        self.ui.tth_max_value.setEnabled(enabled and (not instrument))
        self.ui.tth_max_value.setValue(value)

        tolerances = config.get('tolerance')
        self.tolerances_model.update_from_config(tolerances)

        indexing_config = HexrdConfig().indexing_config
        self.selected_material = indexing_config.get('_selected_material')
        working_dir = indexing_config.get(
            'working_dir', str(Path(HexrdConfig().working_dir).parent))
        analysis_name = indexing_config.get(
            'analysis_name',
            Path(HexrdConfig().working_dir).stem)
        self.spots_path = str(Path(working_dir) / analysis_name)
        write_spots = indexing_config.get('_write_spots', False)
        self.ui.write_out_spots.setChecked(write_spots)

        self.update_num_hkls()

    def run(self):
        self.ui.show()

    def _get_selected_rows(self):
        """Returns list of selected rows

        Rows must be *exclusively* selected. If any partial rows are selected,
        this method returns an empty list.
        """
        selection_model = self.ui.tolerances_view.selectionModel()
        selection = selection_model.selection()
        num_rows = self.tolerances_model.rowCount()
        selected_rows = list()
        for row in range(num_rows):
            if selection_model.isRowSelected(row):
                selected_rows.append(row)
            elif selection_model.rowIntersectsSelection(row):
                # Partial row is selected - return empty list
                del selected_rows[:]
                break

        return selected_rows

    @property
    def material_options(self):
        w = self.ui.material
        return [w.itemText(i) for i in range(w.count())]

    def selected_material_changed(self):
        if hasattr(self, '_table'):
            self._table.material = self.material

        self.update_num_hkls()

    @property
    def selected_material(self):
        return self.ui.material.currentText()

    @selected_material.setter
    def selected_material(self, name):
        if name is None or name not in self.material_options:
            return

        self.ui.material.setCurrentText(name)

    @property
    def material(self):
        return HexrdConfig().material(self.selected_material)

    def choose_hkls(self):
        kwargs = {
            'material': self.material,
            'title_prefix': 'Select hkls for grain fitting: ',
            'parent': self.ui,
        }
        self._table = ReflectionsTable(**kwargs)
        self._table.show()

    def update_num_hkls(self):
        num_hkls = len(self.material.planeData.getHKLs())
        text = f'Number of hkls selected:  {num_hkls}'
        self.ui.num_hkls_selected.setText(text)

    def set_working_dir(self):
        caption = 'Select directory to write spots files to'
        d = QFileDialog.getExistingDirectory(self.ui,
                                             caption,
                                             dir=self.spots_path)

        if d:
            self.spots_path = d
Beispiel #8
0
class OmeMapsSelectDialog(QObject):

    accepted = Signal()
    rejected = Signal()

    def __init__(self, parent=None):
        super().__init__(parent)

        loader = UiLoader()
        self.ui = loader.load_file('ome_maps_select_dialog.ui', parent)
        self.ui.setWindowTitle('Load/Generate Eta Omega Maps')

        # Hide the tab bar. It gets selected by changes to the combo box.
        self.ui.tab_widget.tabBar().hide()
        self.setup_combo_box_data()

        self.update_gui()

        self.setup_connections()

    def setup_connections(self):
        self.ui.select_file_button.pressed.connect(self.select_file)
        self.ui.method.currentIndexChanged.connect(self.update_method_tab)
        self.ui.material.currentIndexChanged.connect(
            self.selected_material_changed)
        self.ui.choose_hkls.pressed.connect(self.choose_hkls)
        self.ui.accepted.connect(self.on_accepted)
        self.ui.rejected.connect(self.on_rejected)

        HexrdConfig().overlay_config_changed.connect(self.update_num_hkls)

    def setup_combo_box_data(self):
        item_data = ['load', 'generate']
        for i, data in enumerate(item_data):
            self.ui.method.setItemData(i, data)

        self.ui.material.clear()
        self.ui.material.addItems(list(HexrdConfig().materials.keys()))
        self.ui.material.setCurrentText(HexrdConfig().active_material_name)

    def show(self):
        self.ui.show()

    def on_accepted(self):
        # Validate
        if self.method_name == 'load' and self.file_name == '':
            msg = 'Please select a file'
            QMessageBox.critical(self.ui, 'HEXRD', msg)
            self.show()
            return

        # Save the selected options on the config
        self.update_config()

        self.accepted.emit()

    def on_rejected(self):
        self.rejected.emit()

    def select_file(self):
        selected_file, selected_filter = QFileDialog.getOpenFileName(
            self.ui, 'Load Eta Omega Maps',
            HexrdConfig().working_dir, 'NPZ files (*.npz)')

        if selected_file:
            HexrdConfig().working_dir = os.path.dirname(selected_file)
            self.ui.file_name.setText(selected_file)

    @property
    def file_name(self):
        return self.ui.file_name.text()

    @property
    def threshold(self):
        if not self.ui.apply_threshold.isChecked():
            return None

        return self.ui.threshold.value()

    @threshold.setter
    def threshold(self, v):
        apply_threshold = v is not None
        self.ui.apply_threshold.setChecked(apply_threshold)
        if apply_threshold:
            self.ui.threshold.setValue(v)

    @property
    def bin_frames(self):
        return self.ui.bin_frames.value()

    @property
    def material_options(self):
        w = self.ui.material
        return [w.itemText(i) for i in range(w.count())]

    def selected_material_changed(self):
        if hasattr(self, '_table'):
            self._table.material = self.material

        self.update_num_hkls()

    @property
    def selected_material(self):
        return self.ui.material.currentText()

    @selected_material.setter
    def selected_material(self, name):
        if name is None or name not in self.material_options:
            return

        self.ui.material.setCurrentText(name)

    @property
    def material(self):
        return HexrdConfig().material(self.selected_material)

    @property
    def widgets(self):
        return [self.ui.file_name, self.ui.threshold, self.ui.bin_frames]

    def update_config(self):
        # Set the new config options on the internal config
        indexing_config = HexrdConfig().indexing_config
        maps_config = indexing_config['find_orientations']['orientation_maps']
        maps_config['file'] = self.file_name
        maps_config['threshold'] = self.threshold
        maps_config['bin_frames'] = self.bin_frames

        indexing_config['_selected_material'] = self.selected_material

    def update_gui(self):
        blockers = [QSignalBlocker(x) for x in self.widgets]  # noqa: F841

        indexing_config = HexrdConfig().indexing_config
        maps_config = indexing_config['find_orientations']['orientation_maps']

        file_name = maps_config['file'] if maps_config['file'] else ''

        self.ui.file_name.setText(file_name)
        self.threshold = maps_config['threshold']
        self.ui.bin_frames.setValue(maps_config['bin_frames'])

        self.selected_material = indexing_config.get('_selected_material')

        self.update_method_tab()

        self.update_num_hkls()

    @property
    def method_name(self):
        return self.ui.method.currentData()

    @method_name.setter
    def method_name(self, v):
        w = self.ui.method
        for i in range(w.count()):
            if v == w.itemData(i):
                w.setCurrentIndex(i)
                return

        raise Exception(f'Unable to set method: {v}')

    def update_method_tab(self):
        # Take advantage of the naming scheme...
        method_tab = getattr(self.ui, self.method_name + '_tab')
        self.ui.tab_widget.setCurrentWidget(method_tab)

    def choose_hkls(self):
        kwargs = {
            'material': self.material,
            'title_prefix': 'Select hkls for eta omega map generation: ',
            'parent': self.ui,
        }
        self._table = ReflectionsTable(**kwargs)
        self._table.show()

    def update_num_hkls(self):
        num_hkls = len(self.material.planeData.getHKLs())
        text = f'Number of hkls selected:  {num_hkls}'
        self.ui.num_hkls_selected.setText(text)