PamhyrToolbar.py 7.79 KiB
# PamhyrToolbar.py -- Pamhyr
# Copyright (C) 2023-2024  INRAE
#
# 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 <https://www.gnu.org/licenses/>.

# -*- coding: utf-8 -*-

import os
import logging
import matplotlib as mpl

from matplotlib.backends import qt_compat
from matplotlib.backends.backend_qt5 import NavigationToolbar2QT

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QAction
from PyQt5.QtCore import pyqtSignal, QSize

_translate = QtCore.QCoreApplication.translate

logger = logging.getLogger()
file_path = os.path.abspath(os.path.dirname(__file__))


class PamhyrPlotToolbar(NavigationToolbar2QT):
    """
    MatPlotLib plot toolbar for Pamhyr
    """
    isometric_signal = pyqtSignal(str)

    def __init__(self, canvas, parent,
                 items=["home", "move", "zoom", "save"]):
        """PamhyrPlotToolbar

        Args:
            canvas: MatPlotLib canvas
            parent: parent Qt object
            items: Enables items (default: "home", "move", "zoom", "save")
        """
        self._canvas = canvas
        self._items = items
        self.toolitems = [
            (None, None, None, None),
        ]

        self.icons = []

        if "home" in items:
            self.init_tool_home()

        if "back/forward" in items:
            self.init_tool_back_forward()

        if "move" in items:
            self.init_tool_move()
            self.add_tool_separator()
        elif "home" in items or "back/forward" in items:
            self.add_tool_separator()

        if "zoom" in items:
            self.init_tool_zoom()

        if "iso" in items:
            self.init_tool_iso()
            self.add_tool_separator()
        elif "zoom" in items:
            self.add_tool_separator()

        if "save" in items:
            self.init_tool_save()

        NavigationToolbar2QT.__init__(self, canvas, parent)
        btn_size = QSize(40, 28)
        actions = self.findChildren(QAction)

        for a, i in self.icons:
            self._actions[a].setIcon(i)

        self.addSeparator()

    def add_tool_separator(self):
        self.toolitems.append((None, None, None, None))

    def init_tool_home(self):
        self.toolitems.append(
            (
                'Home',
                _translate("Toolbar", 'Default view'),
                'home', 'home'
            )
        )

    def init_tool_back_forward(self):
        self.toolitems.append(
            (
                'Back',
                _translate("Toolbar", 'Back to previous view'),
                'back', 'back'
            )
        )
        self.toolitems.append(
            (
                'Forward',
                _translate("Toolbar", 'Return to next view'),
                'forward', 'forward'
            )
        )

    def init_tool_move(self):
        self.toolitems.append(
            (
                'Pan',
                _translate("Toolbar", 'Axes panoramic'),
                'move', 'pan'
            )
        )

    def init_tool_zoom(self):
        self.toolitems.append(
            (
                'Zoom',
                _translate("Toolbar", 'Zoom'),
                'zoom_to_rect', 'zoom'
            )
        )

        icon_zoom = QtGui.QIcon()
        icon_zoom.addPixmap(QtGui.QPixmap(
            os.path.abspath(f"{file_path}/../../ui/ressources/zoom.png")
        ))

        self.icons.append(("zoom", icon_zoom))

    def init_tool_iso(self):
        self.toolitems.append(
            (
                'Isometric_view',
                _translate("Toolbar", 'Isometric view (Shift+W)'),
                '', 'isometric_view'
            )
        )

        self.toolitems.append(
            (
                'GlobalView',
                _translate("Toolbar", 'Auto scale view (Shift+X)'),
                '', 'non_isometric_view'
            )
        )

        icon_btn_isometric_view = QtGui.QIcon()
        icon_btn_isometric_view.addPixmap(
            QtGui.QPixmap(
                os.path.abspath(
                    f"{file_path}/../../ui/ressources/zoom_fit_11.png"
                )
            )
        )

        icon_btn_global_view = QtGui.QIcon()
        icon_btn_global_view.addPixmap(
            QtGui.QPixmap(
                os.path.abspath(
                    f"{file_path}/../../ui/ressources/zoom_fit.png"
                )
            )
        )

        self.icons.append(("isometric_view", icon_btn_isometric_view))
        self.icons.append(("non_isometric_view", icon_btn_global_view))

    def init_tool_save(self):
        self.toolitems.append(
            (
                'Save',
                _translate("Toolbar", 'Save the figure'),
                'filesave', 'save_figure'
            )
        )

        icon_save = QtGui.QIcon()
        icon_save.addPixmap(
            QtGui.QPixmap(
                os.path.abspath(
                    f"{file_path}/../../ui/ressources/save.png"
                )
            )
        )

        self.icons.append(("save_figure", icon_save))

    def save_figure(self, *args):
        file_types = self.canvas.get_supported_filetypes_grouped()
        default_file_type = self.canvas.get_default_filetype()

        start = os.path.join(
            os.path.expanduser(mpl.rcParams['savefig.directory']),
            self.canvas.get_default_filename()
        )

        filters = []
        selected_filter = None
        for name in file_types:
            exts = file_types[name]
            exts_list = " ".join([f"*.{ext}" for ext in exts])
            new = f"{name} ({exts_list})"

            if default_file_type in exts:
                selected_filter = new

            filters.append(new)
        filters = ';;'.join(filters)

        file_name, _ = qt_compat._getSaveFileName(
            self.canvas.parent(),
            _translate("MainWindow_reach", "Select destination file"),
            start, filters,
            selected_filter
        )

        if file_name:
            try:
                self.canvas.figure.savefig(file_name)
            except Exception as e:
                QtWidgets.QMessageBox.critical(
                    self, "Error saving file", str(e),
                    QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.NoButton
                )

    def isometric_view(self):
        self._canvas.axes.axis("equal")
        self._canvas.figure.canvas.draw_idle()
        self.isometric_signal[str].emit("vue iso")

    def non_isometric_view(self):
        self._canvas.axes.axis("tight")
        self._canvas.toolbar.update()
        self._canvas.figure.canvas.draw_idle()

    def toolitems_translation(self):
        self._actions['home'].setToolTip(_translate("Toolbar", "Default view"))
        self._actions['back'].setToolTip(
            _translate("Toolbar", "Back to previous view"))
        self._actions['forward'].setToolTip(
            _translate("Toolbar", "Return to next view"))
        self._actions['pan'].setToolTip(
            _translate("Toolbar", "Axes panoramic"))
        self._actions['zoom'].setToolTip(_translate("Toolbar", "Zoom"))
        self._actions['save_figure'].setToolTip(
            _translate("Toolbar", "Save the figure"))
        self.action_isometric_view.setToolTip(
            _translate("Toolbar", "Isometric view (Shift+W)"))
        self.action_auto_global_view.setToolTip(
            _translate("Toolbar", "Auto scale view (Shift+X)"))