mirror of https://github.com/Dioptas/Dioptas.git
361 lines
14 KiB
Python
361 lines
14 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Dioptas - GUI program for fast processing of 2D X-ray diffraction data
|
|
# Principal author: Clemens Prescher (clemens.prescher@gmail.com)
|
|
# Copyright (C) 2014-2019 GSECARS, University of Chicago, USA
|
|
# Copyright (C) 2015-2018 Institute for Geology and Mineralogy, University of Cologne, Germany
|
|
# Copyright (C) 2019-2020 DESY, Hamburg, Germany
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import os
|
|
|
|
from qtpy import QtWidgets, QtGui
|
|
from ....widgets.UtilityWidgets import open_files_dialog
|
|
|
|
# imports for type hinting in PyCharm -- DO NOT DELETE
|
|
from ....widgets.integration import IntegrationWidget
|
|
from ....model.DioptasModel import DioptasModel
|
|
|
|
|
|
class OverlayController(object):
|
|
"""
|
|
IntegrationOverlayController handles all the interaction between the Overlay controls of the integration view and
|
|
the corresponding overlay data in the Pattern Model.
|
|
"""
|
|
|
|
def __init__(self, widget: IntegrationWidget, dioptas_model: DioptasModel):
|
|
"""
|
|
:param widget: Reference to IntegrationWidget object
|
|
:param pattern_model: Reference to PatternModel object
|
|
"""
|
|
self.integration_widget = widget
|
|
self.overlay_widget = self.integration_widget.overlay_widget
|
|
self.model = dioptas_model
|
|
|
|
self.overlay_lw_items = []
|
|
self.create_signals()
|
|
|
|
def create_signals(self):
|
|
self.connect_click_function(
|
|
self.overlay_widget.add_btn, self.add_overlay_btn_click_callback
|
|
)
|
|
self.connect_click_function(
|
|
self.overlay_widget.delete_btn, self.delete_btn_click_callback
|
|
)
|
|
self.connect_click_function(
|
|
self.overlay_widget.move_up_btn, self.move_up_overlay_btn_click_callback
|
|
)
|
|
self.connect_click_function(
|
|
self.overlay_widget.move_down_btn, self.move_down_overlay_btn_click_callback
|
|
)
|
|
self.overlay_widget.clear_btn.clicked.connect(
|
|
self.clear_overlays_btn_click_callback
|
|
)
|
|
|
|
self.overlay_widget.overlay_tw.currentCellChanged.connect(self.overlay_selected)
|
|
self.overlay_widget.color_btn_clicked.connect(self.color_btn_clicked)
|
|
self.overlay_widget.show_cb_state_changed.connect(
|
|
self.model.overlay_model.set_overlay_visible
|
|
)
|
|
self.overlay_widget.name_changed.connect(self.rename_overlay)
|
|
|
|
self.overlay_widget.scale_step_msb.valueChanged.connect(self.update_scale_step)
|
|
self.overlay_widget.offset_step_msb.valueChanged.connect(
|
|
self.update_overlay_offset_step
|
|
)
|
|
self.overlay_widget.scale_sb_value_changed.connect(self.scale_sb_changed)
|
|
self.overlay_widget.offset_sb_value_changed.connect(self.offset_sb_changed)
|
|
|
|
self.overlay_widget.waterfall_btn.clicked.connect(
|
|
self.waterfall_btn_click_callback
|
|
)
|
|
self.overlay_widget.waterfall_reset_btn.clicked.connect(
|
|
self.model.overlay_model.reset_overlay_offsets
|
|
)
|
|
|
|
self.overlay_widget.set_as_bkg_btn.clicked.connect(
|
|
self.set_as_bkg_btn_click_callback
|
|
)
|
|
|
|
self.overlay_widget.overlay_tw.horizontalHeader().sectionClicked.connect(
|
|
self.overlay_tw_header_section_clicked
|
|
)
|
|
|
|
# creating the quick-actions signals
|
|
|
|
self.connect_click_function(
|
|
self.integration_widget.qa_set_as_overlay_btn,
|
|
self.set_current_pattern_as_overlay,
|
|
)
|
|
self.connect_click_function(
|
|
self.integration_widget.qa_set_as_background_btn,
|
|
self.set_current_pattern_as_background,
|
|
)
|
|
|
|
# pattern_data signals
|
|
self.model.overlay_model.overlay_added.connect(self.overlay_added)
|
|
self.model.overlay_model.overlay_removed.connect(self.overlay_removed)
|
|
self.model.overlay_model.overlay_changed.connect(self.overlay_changed)
|
|
|
|
def connect_click_function(self, emitter, function):
|
|
emitter.clicked.connect(function)
|
|
|
|
def add_overlay_btn_click_callback(self):
|
|
filenames = open_files_dialog(
|
|
self.integration_widget,
|
|
"Load Overlay(s).",
|
|
self.model.working_directories["overlay"],
|
|
)
|
|
if len(filenames):
|
|
for filename in filenames:
|
|
filename = str(filename)
|
|
self.model.overlay_model.add_overlay_file(filename)
|
|
self.model.working_directories["overlay"] = os.path.dirname(
|
|
str(filenames[0])
|
|
)
|
|
|
|
def overlay_added(self):
|
|
"""
|
|
callback when overlay is added to the PatternData
|
|
"""
|
|
color = self.model.overlay_model.get_overlay_color(
|
|
len(self.model.overlay_model.overlays) - 1
|
|
)
|
|
self.overlay_widget.add_overlay(
|
|
self.model.overlay_model.overlays[-1].name, color
|
|
)
|
|
|
|
def delete_btn_click_callback(self):
|
|
"""
|
|
Removes the currently in the overlay table selected overlay from the table, pattern_data and pattern_view
|
|
"""
|
|
cur_ind = self.overlay_widget.get_selected_overlay_row()
|
|
if cur_ind < 0:
|
|
return
|
|
if (
|
|
self.model.pattern_model.background_pattern
|
|
== self.model.overlay_model.overlays[cur_ind]
|
|
):
|
|
self.model.pattern_model.background_pattern = None
|
|
self.model.overlay_model.remove_overlay(cur_ind)
|
|
|
|
def overlay_removed(self, ind):
|
|
"""
|
|
callback when overlay is removed from PatternData
|
|
:param ind: index of overlay removed
|
|
"""
|
|
self.overlay_widget.remove_overlay(ind)
|
|
|
|
# if no more overlays are present the set_as_bkg_btn should be unchecked
|
|
if self.overlay_widget.overlay_tw.rowCount() == 0:
|
|
self.overlay_widget.set_as_bkg_btn.setChecked(False)
|
|
|
|
def move_up_overlay_btn_click_callback(self):
|
|
cur_ind = self.overlay_widget.get_selected_overlay_row()
|
|
if cur_ind < 1:
|
|
return
|
|
|
|
self.model.overlay_model.move_overlay_up(cur_ind)
|
|
self.overlay_widget.overlay_tw.selectRow(cur_ind - 1)
|
|
|
|
def move_down_overlay_btn_click_callback(self):
|
|
cur_ind = self.overlay_widget.get_selected_overlay_row()
|
|
if cur_ind < 0 or cur_ind >= self.integration_widget.overlay_tw.rowCount() - 1:
|
|
return
|
|
|
|
self.model.overlay_model.move_overlay_down(cur_ind)
|
|
self.overlay_widget.overlay_tw.selectRow(cur_ind + 1)
|
|
|
|
def clear_overlays_btn_click_callback(self):
|
|
"""
|
|
removes all currently loaded overlays
|
|
"""
|
|
while self.integration_widget.overlay_tw.rowCount() > 0:
|
|
self.delete_btn_click_callback()
|
|
|
|
def update_scale_step(self):
|
|
"""
|
|
Sets the step size for the scale spinboxes from the step text box.
|
|
"""
|
|
value = self.overlay_widget.scale_step_msb.value()
|
|
for scale_sb in self.overlay_widget.scale_sbs:
|
|
scale_sb.setSingleStep(value)
|
|
|
|
def update_overlay_offset_step(self):
|
|
"""
|
|
Sets the step size for the offset spinbox from the offset_step text box.
|
|
"""
|
|
value = self.overlay_widget.offset_step_msb.value()
|
|
for offset_sb in self.overlay_widget.offset_sbs:
|
|
offset_sb.setSingleStep(value)
|
|
|
|
def overlay_selected(self, row, *_):
|
|
"""
|
|
Callback when the selected row in the overlay table is changed. It will update the scale and offset values
|
|
for the newly selected overlay and check whether it is set as background or not and check the
|
|
the set_as_bkg_btn appropriately.
|
|
:param row: selected row in the overlay table
|
|
"""
|
|
if (
|
|
self.model.pattern_model.background_pattern is
|
|
self.model.overlay_model.overlays[row]
|
|
):
|
|
self.overlay_widget.set_as_bkg_btn.setChecked(True)
|
|
else:
|
|
self.overlay_widget.set_as_bkg_btn.setChecked(False)
|
|
|
|
def color_btn_clicked(self, ind, button):
|
|
"""
|
|
Callback for the color buttons in the overlay table. Opens up a color dialog. The color of the overlay and
|
|
its respective button will be changed according to the selection
|
|
:param ind: overlay ind
|
|
:param button: button to color
|
|
"""
|
|
previous_color = button.palette().color(QtGui.QPalette.Button)
|
|
new_color = QtWidgets.QColorDialog.getColor(
|
|
previous_color, self.integration_widget
|
|
)
|
|
if new_color.isValid():
|
|
color = str(new_color.name())
|
|
else:
|
|
color = str(previous_color.name())
|
|
self.model.overlay_model.set_overlay_color(ind, color)
|
|
|
|
def scale_sb_changed(self, overlay_ind, new_value):
|
|
"""
|
|
Callback for scale_sb spinbox.
|
|
:param overlay_ind: index of overlay
|
|
:param new_value: new scale value
|
|
"""
|
|
self.model.overlay_model.set_overlay_scaling(overlay_ind, new_value)
|
|
if (
|
|
self.model.overlay_model.overlays[overlay_ind]
|
|
== self.model.pattern_model.background_pattern
|
|
):
|
|
self.model.pattern_changed.emit()
|
|
|
|
def offset_sb_changed(self, overlay_ind, new_value):
|
|
"""
|
|
Callback gor the offset_sb spinbox.
|
|
:param overlay_ind: index of overlay
|
|
:param new_value: new value
|
|
"""
|
|
self.model.overlay_model.set_overlay_offset(overlay_ind, new_value)
|
|
if (
|
|
self.model.overlay_model.overlays[overlay_ind]
|
|
== self.model.pattern_model.background_pattern
|
|
):
|
|
self.model.pattern_changed.emit()
|
|
|
|
def overlay_changed(self, ind):
|
|
self.overlay_widget.offset_sbs[ind].blockSignals(True)
|
|
self.overlay_widget.scale_sbs[ind].blockSignals(True)
|
|
self.overlay_widget.offset_sbs[ind].setValue(
|
|
self.model.overlay_model.get_overlay_offset(ind)
|
|
)
|
|
self.overlay_widget.scale_sbs[ind].setValue(
|
|
self.model.overlay_model.get_overlay_scaling(ind)
|
|
)
|
|
self.overlay_widget.offset_sbs[ind].blockSignals(False)
|
|
self.overlay_widget.scale_sbs[ind].blockSignals(False)
|
|
|
|
color = self.model.overlay_model.get_overlay_color(ind)
|
|
self.overlay_widget.color_btns[ind].setStyleSheet(
|
|
f"background-color: {color}; margin: 2px"
|
|
)
|
|
|
|
overlay = self.model.overlay_model.overlays[ind]
|
|
self.overlay_widget.set_overlay_name(ind, overlay.name)
|
|
|
|
def waterfall_btn_click_callback(self):
|
|
separation = self.overlay_widget.waterfall_separation_msb.value()
|
|
self.model.overlay_model.overlay_waterfall(separation)
|
|
|
|
def set_as_bkg_btn_click_callback(self):
|
|
"""
|
|
Callback for the set_as_bkg_btn QPushButton. Will try to either set the currently selected overlay as
|
|
background or unset if it already. Any other overlay which was set before as bkg will
|
|
"""
|
|
cur_ind = self.overlay_widget.get_selected_overlay_row()
|
|
if cur_ind == -1: # no overlay selected
|
|
self.overlay_widget.set_as_bkg_btn.setChecked(False)
|
|
return
|
|
|
|
if not self.overlay_widget.set_as_bkg_btn.isChecked():
|
|
## if the overlay is not currently a background
|
|
# it will unset the current background and redisplay
|
|
self.model.pattern_model.background_pattern = None
|
|
else:
|
|
# if the overlay is currently the active background
|
|
self.model.pattern_model.background_pattern = (
|
|
self.model.overlay_model.overlays[cur_ind]
|
|
)
|
|
if self.overlay_widget.show_cb_is_checked(cur_ind):
|
|
self.overlay_widget.show_cb_set_checked(cur_ind, False)
|
|
|
|
def set_current_pattern_as_overlay(self):
|
|
self.model.overlay_model.add_overlay_pattern(self.model.pattern)
|
|
|
|
def set_current_pattern_as_background(self):
|
|
self.model.overlay_model.add_overlay_pattern(self.model.pattern)
|
|
self.model.pattern_model.background_pattern = self.model.overlay_model.overlays[
|
|
-1
|
|
]
|
|
|
|
self.overlay_widget.set_as_bkg_btn.setChecked(True)
|
|
self.overlay_widget.show_cb_set_checked(-1, False)
|
|
|
|
def overlay_set_as_bkg(self, ind):
|
|
cur_selected_ind = self.overlay_widget.get_selected_overlay_row()
|
|
self.overlay_widget.set_as_bkg_btn.setChecked(ind == cur_selected_ind)
|
|
# hide the original overlay
|
|
if self.overlay_widget.show_cb_is_checked(ind):
|
|
self.overlay_widget.show_cb_set_checked(ind, False)
|
|
|
|
def overlay_unset_as_bkg(self, ind):
|
|
self.overlay_widget.show_cb_set_checked(ind, True)
|
|
if self.model.pattern_model.bkg_ind == -1:
|
|
self.overlay_widget.set_as_bkg_btn.setChecked(False)
|
|
|
|
def show_cb_state_changed(self, ind, state):
|
|
"""
|
|
Callback for the checkboxes in the overlay tablewidget. Controls the visibility of the overlay in the pattern
|
|
view
|
|
:param ind: index of overlay
|
|
:param state: boolean value whether the checkbox was checked or unchecked
|
|
"""
|
|
self.model.overlay_model.set_overlay_visible(ind, state)
|
|
|
|
def rename_overlay(self, ind, name):
|
|
"""
|
|
Callback for changing the name in the overlay tablewidget (by double clicking the name and entering a new one).
|
|
This will update the visible name in the pattern view
|
|
:param ind: index of overlay for which the name was changed
|
|
:param name: new name
|
|
"""
|
|
self.model.overlay_model.set_overlay_name(ind, name)
|
|
|
|
def overlay_tw_header_section_clicked(self, ind):
|
|
if ind != 0:
|
|
return
|
|
|
|
current_checkbox_state = False
|
|
# check whether any checkbox is checked, if one is true current_checkbox_state will be True too
|
|
for cb in self.overlay_widget.show_cbs:
|
|
current_checkbox_state = current_checkbox_state or cb.isChecked()
|
|
|
|
# assign the the opposite to all checkboxes
|
|
for cb in self.overlay_widget.show_cbs:
|
|
cb.setChecked(not current_checkbox_state)
|