diff --git a/src/mslice/plotting/plot_window/cut_plot.py b/src/mslice/plotting/plot_window/cut_plot.py index 05df44ed..9214923a 100644 --- a/src/mslice/plotting/plot_window/cut_plot.py +++ b/src/mslice/plotting/plot_window/cut_plot.py @@ -29,6 +29,7 @@ DEFAULT_LABEL_SIZE = 10 DEFAULT_TITLE_SIZE = 12 +DEFAULT_FONT_SIZE_STEP = 1 def get_min(data, absolute_minimum=-np.inf): @@ -65,6 +66,13 @@ def __init__(self, figure_manager, cut_plotter_presenter, workspace_name): self._intensity_type = IntensityType.SCATTERING_FUNCTION self._intensity_correction_flag = False self._temp_dependent = False + self.plot_fonts_properties = [ + 'title_size', + 'x_range_font_size', + 'y_range_font_size', + 'x_label_size', + 'y_label_size', + ] def save_default_options(self): self.default_options = { @@ -707,6 +715,10 @@ def title(self, value): def title_size(self): return self.manager.title_size + @title_size.setter + def title_size(self, value): + self.manager.title_size = value + @property def x_label(self): return self.manager.x_label @@ -722,6 +734,10 @@ def x_label(self, value): def x_label_size(self): return self.manager.x_label_size + @x_label_size.setter + def x_label_size(self, value): + self.manager.x_label_size = value + @property def y_label(self): return self.manager.y_label @@ -737,6 +753,10 @@ def y_label(self, value): def y_label_size(self): return self.manager.y_label_size + @y_label_size.setter + def y_label_size(self, value): + self.manager.y_label_size = value + @property def x_range(self): return self.manager.x_range @@ -817,3 +837,24 @@ def is_changed(self, item): @property def intensity_type(self): return self._intensity_type + + @property + def all_fonts_size(self): + font_sizes_config = {} + for p in self.plot_fonts_properties: + font_sizes_config[p] = getattr(self, p) + + return font_sizes_config + + @all_fonts_size.setter + def all_fonts_size(self, values: dict): + for key in values: + setattr(self, key, values[key]) + + def increase_all_fonts(self): + for p in self.plot_fonts_properties: + setattr(self, p, getattr(self, p) + DEFAULT_FONT_SIZE_STEP) + + def decrease_all_fonts(self): + for p in self.plot_fonts_properties: + setattr(self, p, getattr(self, p) - DEFAULT_FONT_SIZE_STEP) diff --git a/src/mslice/plotting/plot_window/plot_figure_manager.py b/src/mslice/plotting/plot_window/plot_figure_manager.py index 19a53532..7b9b6fc7 100644 --- a/src/mslice/plotting/plot_window/plot_figure_manager.py +++ b/src/mslice/plotting/plot_window/plot_figure_manager.py @@ -305,17 +305,21 @@ def figure(self): @property def title(self): - return self.figure.gca().get_title() + return self.figure.gca().title.get_text() @title.setter def title(self, value): - self.figure.gca().set_title(value) + self.figure.gca().title.set_text(value) self.window.setWindowTitle(value) @property def title_size(self): return self.figure.gca().title.get_size() + @title_size.setter + def title_size(self, value): + self.figure.gca().title.set_size(value) + @property def x_label(self): return self.figure.gca().get_xlabel() @@ -328,6 +332,10 @@ def x_label(self, value): def x_label_size(self): return self.figure.gca().xaxis.label.get_size() + @x_label_size.setter + def x_label_size(self, value): + self.figure.gca().xaxis.label.set_size(value) + @property def y_label(self): return self.figure.gca().get_ylabel() @@ -340,6 +348,10 @@ def y_label(self, value): def y_label_size(self): return self.figure.gca().yaxis.label.get_size() + @y_label_size.setter + def y_label_size(self, value): + self.figure.gca().yaxis.label.set_size(value) + @property def x_range(self): return self.figure.gca().get_xlim() diff --git a/src/mslice/plotting/plot_window/plot_options.py b/src/mslice/plotting/plot_window/plot_options.py index e2e4e066..d795cef9 100644 --- a/src/mslice/plotting/plot_window/plot_options.py +++ b/src/mslice/plotting/plot_window/plot_options.py @@ -7,8 +7,10 @@ from qtpy.QtCore import Signal from mslice.models.colors import named_cycle_colors, color_to_name from mslice.util.qt import load_ui - +from qtpy.QtGui import QRegExpValidator +from qtpy.QtCore import QRegExp from mantidqt.utils.qt.line_edit_double_validator import LineEditDoubleValidator +from mantidqt.icons import get_icon class PlotOptionsDialog(QtWidgets.QDialog): @@ -20,12 +22,19 @@ class PlotOptionsDialog(QtWidgets.QDialog): yRangeEdited = Signal() xGridEdited = Signal() yGridEdited = Signal() + allFontSizeEdited = Signal() + fontSizeUpClicked = Signal() + fontSizeDownClicked = Signal() + allFontSizeFromEmptyToValue = Signal() ok_clicked = Signal() def __init__(self, parent, redraw_signal=None): QtWidgets.QDialog.__init__(self, parent) load_ui(__file__, 'plot_options.ui', self) + self.sclUpFntSz.setIcon(get_icon("mdi.arrow-up")) + self.sclDownFntSz.setIcon(get_icon("mdi.arrow-down")) + self.x_min_validator = LineEditDoubleValidator(self.lneXMin, 0.0) self.lneXMin.setValidator(self.x_min_validator) self.x_max_validator = LineEditDoubleValidator(self.lneXMax, 0.0) @@ -34,6 +43,9 @@ def __init__(self, parent, redraw_signal=None): self.lneYMin.setValidator(self.y_min_validator) self.y_max_validator = LineEditDoubleValidator(self.lneYMax, 0.0) self.lneYMax.setValidator(self.y_max_validator) + two_postv_ints_regex = QRegExp(r"^\s*[1-9][0-9]?$") + self.all_fonts_size_validator = QRegExpValidator(two_postv_ints_regex) + self.allFntSz.setValidator(self.all_fonts_size_validator) self.lneFigureTitle.editingFinished.connect(self.titleEdited) self.lneXAxisLabel.editingFinished.connect(self.xLabelEdited) @@ -46,8 +58,31 @@ def __init__(self, parent, redraw_signal=None): self.buttonBox.rejected.connect(self.reject) self.chkXGrid.stateChanged.connect(self.xGridEdited) self.chkYGrid.stateChanged.connect(self.yGridEdited) + + self.allFntSz.textEdited.connect(self._font_sizes_changed) + self.sclUpFntSz.clicked.connect(self._scale_up_fonts_clicked) + self.sclDownFntSz.clicked.connect(self._scale_down_fonts_clicked) + self.redraw_signal = redraw_signal + self.allFntSzBuffer = '' + + def _font_sizes_changed(self): + if self.allFntSzBuffer == '': + self.allFontSizeFromEmptyToValue.emit() + self.allFntSzBuffer = str(self.allFntSz.text()) + + self.allFontSizeEdited.emit() + self.redraw_signal.emit() + + def _scale_up_fonts_clicked(self): + self.fontSizeUpClicked.emit() + self.redraw_signal.emit() + + def _scale_down_fonts_clicked(self): + self.fontSizeDownClicked.emit() + self.redraw_signal.emit() + def _ok_clicked(self): self.ok_clicked.emit() self.redraw_signal.emit() @@ -134,6 +169,17 @@ def y_grid(self, value): def is_kept_open(self): return self.keep_open.isChecked() + @property + def all_fonts_size(self): + try: + return float(str(self.allFntSz.text())) + except ValueError: + return None + + @all_fonts_size.setter + def all_fonts_size(self, value): + self.allFntSz.setText(str(value)) + class SlicePlotOptions(PlotOptionsDialog): diff --git a/src/mslice/plotting/plot_window/plot_options.ui b/src/mslice/plotting/plot_window/plot_options.ui index 1f1998f8..b26341a7 100644 --- a/src/mslice/plotting/plot_window/plot_options.ui +++ b/src/mslice/plotting/plot_window/plot_options.ui @@ -231,6 +231,40 @@ + + + + Figure Fonts + + + + + + Set all fonts size + + + + + + + + 16777215 + 16777215 + + + + + + + + + + + + + + + diff --git a/src/mslice/plotting/plot_window/slice_plot.py b/src/mslice/plotting/plot_window/slice_plot.py index a5e377ca..03af7ff9 100644 --- a/src/mslice/plotting/plot_window/slice_plot.py +++ b/src/mslice/plotting/plot_window/slice_plot.py @@ -27,6 +27,7 @@ DEFAULT_LABEL_SIZE = 10 DEFAULT_TITLE_SIZE = 12 +DEFAULT_FONT_SIZE_STEP = 1 class SlicePlot(IPlot): @@ -54,6 +55,15 @@ def __init__(self, figure_manager, slice_plotter_presenter, workspace_name): self.temp_dependent = False self.temp = None self.default_options = None + self.plot_fonts_properties = [ + 'title_size', + 'x_range_font_size', + 'y_range_font_size', + 'x_label_size', + 'y_label_size', + 'colorbar_label_size', + 'colorbar_range_font_size' + ] def save_default_options(self): self.default_options = { @@ -473,6 +483,10 @@ def colorbar_label(self, value): def colorbar_label_size(self): return self._canvas.figure.get_axes()[1].yaxis.label.get_size() + @colorbar_label_size.setter + def colorbar_label_size(self, value): + self._canvas.figure.get_axes()[1].yaxis.label.set_size(value) + @property def colorbar_range(self): return self._canvas.figure.gca().collections[0].get_clim() @@ -512,6 +526,10 @@ def title(self, value): def title_size(self): return self.manager.title_size + @title_size.setter + def title_size(self, value): + self.manager.title_size = value + @property def x_label(self): return self.manager.x_label @@ -527,6 +545,10 @@ def x_label(self, value): def x_label_size(self): return self.manager.x_label_size + @x_label_size.setter + def x_label_size(self, value): + self.manager.x_label_size = value + @property def y_label(self): return self.manager.y_label @@ -542,6 +564,10 @@ def y_label(self, value): def y_label_size(self): return self.manager.y_label_size + @y_label_size.setter + def y_label_size(self, value): + self.manager.y_label_size = value + @property def x_range(self): return self.manager.x_range @@ -613,3 +639,24 @@ def _get_overplot_datum(): # needed for interface consistency with cut plot def set_cross_cursor(self): self._canvas.setCursor(Qt.CrossCursor) + + @property + def all_fonts_size(self): + font_sizes_config = {} + for p in self.plot_fonts_properties: + font_sizes_config[p] = getattr(self, p) + + return font_sizes_config + + @all_fonts_size.setter + def all_fonts_size(self, values: dict): + for key in values: + setattr(self, key, values[key]) + + def increase_all_fonts(self): + for p in self.plot_fonts_properties: + setattr(self, p, getattr(self, p) + DEFAULT_FONT_SIZE_STEP) + + def decrease_all_fonts(self): + for p in self.plot_fonts_properties: + setattr(self, p, getattr(self, p) - DEFAULT_FONT_SIZE_STEP) diff --git a/src/mslice/presenters/plot_options_presenter.py b/src/mslice/presenters/plot_options_presenter.py index b91b2bfb..fe1aa4aa 100644 --- a/src/mslice/presenters/plot_options_presenter.py +++ b/src/mslice/presenters/plot_options_presenter.py @@ -9,6 +9,7 @@ def __init__(self, plot_options_dialog, plot_handler): self._view = plot_options_dialog self._modified_values = {} self._xy_config = {'x_range': self._model.x_range, 'y_range': self._model.y_range, 'modified': False} + self._default_font_sizes_config = {} self.set_properties() # propagate dialog with existing data @@ -19,6 +20,12 @@ def __init__(self, plot_options_dialog, plot_handler): self._view.yRangeEdited.connect(partial(self._xy_config_modified, 'y_range')) self._view.xGridEdited.connect(partial(self._value_modified, 'x_grid')) self._view.yGridEdited.connect(partial(self._value_modified, 'y_grid')) + self._view.allFontSizeFromEmptyToValue.connect(self._update_font_sizes_buffer) + self._view.allFontSizeEdited.connect(self._set_all_plot_fonts) + self._view.fontSizeUpClicked.connect(self._model.increase_all_fonts) + self._view.fontSizeDownClicked.connect(self._model.decrease_all_fonts) + self._view.redraw_signal.connect(self._set_font_sizes_tooltip) + self._set_font_sizes_tooltip() def _value_modified(self, value_name): self._modified_values[value_name] = getattr(self._view, value_name) @@ -27,6 +34,31 @@ def _xy_config_modified(self, key): getattr(self, '_xy_config')[key] = getattr(self._view, key) self._xy_config['modified'] = True + def _update_font_sizes_buffer(self): + self._default_font_sizes_config = self._model.all_fonts_size.copy() + + def _set_all_plot_fonts(self): + new_config_dict = self._default_font_sizes_config.copy() + + fonts_size = self._view.all_fonts_size + if fonts_size is not None: + new_config_dict = {key: fonts_size for key in new_config_dict} + + self._model.all_fonts_size = new_config_dict + + def _set_font_sizes_tooltip(self): + tip = self._convert_font_config_to_tooltip() + self._view.allFntSz.setToolTip(tip) + self._view.sclUpFntSz.setToolTip("Increase font sizes\n\n" + tip) + self._view.sclDownFntSz.setToolTip("Decrease font sizes\n\n" + tip) + + def _convert_font_config_to_tooltip(self): + font_size_dict = self._model.all_fonts_size.copy() + tip = str(font_size_dict)[1:-1].replace(', ', '\n').replace('_', ' ') + for str_to_remove in ['size', 'font', "'"]: + tip = tip.replace(str_to_remove, '') + return tip + class SlicePlotOptionsPresenter(PlotOptionsPresenter): @@ -38,6 +70,7 @@ def __init__(self, plot_options_dialog, slice_handler): self._view.cLogEdited.connect(self._set_colorbar_log) self._view.cRangeEdited.connect(self._set_c_range) self._view.ok_clicked.connect(self.get_new_config) + self._view.show() def set_properties(self): diff --git a/tests/cut_plot_test.py b/tests/cut_plot_test.py index 7a092561..4fcc537c 100644 --- a/tests/cut_plot_test.py +++ b/tests/cut_plot_test.py @@ -130,3 +130,26 @@ def test_waterfall(self): self.cut_plot.toggle_waterfall() self.cut_plot._apply_offset.assert_called_with(0, 0) self.cut_plot.update_bragg_peaks.assert_called_with(refresh=True) + + def test_all_fonts_size(self): + fonts_config = {'title_size': 15, 'x_range_font_size': 14, 'y_range_font_size': 13, + 'x_label_size': 12, 'y_label_size': 11} + + self.cut_plot.all_fonts_size = fonts_config + self.assertEqual(self.cut_plot.title_size, 15) + self.assertEqual(self.cut_plot.x_range_font_size, 14) + self.assertEqual(self.cut_plot.y_range_font_size, 13) + self.assertEqual(self.cut_plot.x_label_size, 12) + self.assertEqual(self.cut_plot.y_label_size, 11) + + def test_increment_all_fonts(self): + fonts_config = {'title_size': 15, 'x_range_font_size': 14, 'y_range_font_size': 13, + 'x_label_size': 12, 'y_label_size': 11} + self.cut_plot.all_fonts_size = fonts_config + + self.cut_plot.increase_all_fonts() + self.assertEqual(self.cut_plot.title_size, 16) + self.assertEqual(self.cut_plot.x_range_font_size, 15) + self.assertEqual(self.cut_plot.y_range_font_size, 14) + self.assertEqual(self.cut_plot.x_label_size, 13) + self.assertEqual(self.cut_plot.y_label_size, 12) diff --git a/tests/plot_options_presenter_test.py b/tests/plot_options_presenter_test.py index 2b86b161..7620099a 100644 --- a/tests/plot_options_presenter_test.py +++ b/tests/plot_options_presenter_test.py @@ -185,7 +185,7 @@ def test_change_xy_log(self): self.presenter._xy_config_modified('y_log') self.presenter.get_new_config() self.model.change_axis_scale.assert_called_once_with({'x_range': (1, 2), 'y_range': (3, 4), 'modified': True, - 'x_log': False, 'y_log': True}) + 'x_log': False, 'y_log': True}) def test_line_options(self): # model -> view @@ -216,3 +216,24 @@ def test_remove_line(self): # check line with correct index removed self.presenter.remove_container(9) self.model.remove_line_by_index.assert_called_once_with(9) + + def test_set_all_fonts_size(self): + model_all_fonts_size = PropertyMock() + view_all_fonts_size = PropertyMock() + type(self.model).all_fonts_size = model_all_fonts_size + type(self.view).all_fonts_size = view_all_fonts_size + + self.presenter = CutPlotOptionsPresenter(self.view, self.model) + fonts_config = {'title_size': 15, 'x_range_font_size': 14, 'y_range_font_size': 13, + 'x_label_size': 12, 'y_label_size': 11} + self.presenter._default_font_sizes_config = fonts_config + + # view -> model + view_all_fonts_size.return_value = 20 + self.presenter._set_all_plot_fonts() + + view_all_fonts_size.assert_called_once_with() + + fonts_updated = {'title_size': 20, 'x_range_font_size': 20, 'y_range_font_size': 20, + 'x_label_size': 20, 'y_label_size': 20} + model_all_fonts_size.assert_any_call(fonts_updated) # Not latest call due to copy() methods diff --git a/tests/slice_plot_test.py b/tests/slice_plot_test.py index a78eec6c..9cec1e78 100644 --- a/tests/slice_plot_test.py +++ b/tests/slice_plot_test.py @@ -117,6 +117,47 @@ def test_update_legend_in_slice_plot(self): self.slice_plot.update_legend() mock_add_legend.assert_called_with(self.line, ['some_label'], fontsize=ANY, loc='upper right') + def test_all_fonts_size(self): + slice_plot_colorbar_label_size = PropertyMock() + slice_plot_colorbar_range_font_size = PropertyMock() + type(self.slice_plot).colorbar_label_size = slice_plot_colorbar_label_size + type(self.slice_plot).colorbar_range_font_size = slice_plot_colorbar_range_font_size + + fonts_config = {'title_size': 15, 'x_range_font_size': 14, 'y_range_font_size': 13, + 'x_label_size': 12, 'y_label_size': 11, 'colorbar_label_size': 10, + 'colorbar_range_font_size': 9} + + self.slice_plot.all_fonts_size = fonts_config + + slice_plot_colorbar_range_font_size.assert_called_once_with(9) + slice_plot_colorbar_label_size.assert_called_once_with(10) + + self.assertEqual(self.slice_plot.title_size, 15) + self.assertEqual(self.slice_plot.x_range_font_size, 14) + self.assertEqual(self.slice_plot.y_range_font_size, 13) + self.assertEqual(self.slice_plot.x_label_size, 12) + self.assertEqual(self.slice_plot.y_label_size, 11) + + def test_increase_all_fonts(self): + mock_colorbar_label_size = PropertyMock(return_value=9) + mock_colorbar_range_font_size = PropertyMock(return_value=10) + type(self.slice_plot).colorbar_label_size = mock_colorbar_label_size + type(self.slice_plot).colorbar_range_font_size = mock_colorbar_range_font_size + + fonts_config = {'title_size': 15, 'x_range_font_size': 14, 'y_range_font_size': 13, + 'x_label_size': 12, 'y_label_size': 11} + self.slice_plot.all_fonts_size = fonts_config + + self.slice_plot.increase_all_fonts() + + self.assertEqual(self.slice_plot.title_size, 16) + self.assertEqual(self.slice_plot.x_range_font_size, 15) + self.assertEqual(self.slice_plot.y_range_font_size, 14) + self.assertEqual(self.slice_plot.x_label_size, 13) + self.assertEqual(self.slice_plot.y_label_size, 12) + mock_colorbar_label_size.assert_called_with(10) + mock_colorbar_range_font_size.assert_called_with(11) + if __name__ == '__main__': unittest.main()