From 2b457d5fb087a6609db3ea7121d501d9429c75b3 Mon Sep 17 00:00:00 2001
From: Oscar Gustafsson <oscar.gustafsson@liu.se>
Date: Sat, 29 Apr 2023 21:16:27 +0000
Subject: [PATCH] Add zoom to fit

---
 b_asic/GUI/main_window.py              | 18 +++++++++++++++++-
 b_asic/gui_utils/icons.py              | 10 +++++++++-
 b_asic/scheduler_gui/main_window.py    | 13 +++++++++++++
 b_asic/scheduler_gui/main_window.ui    | 23 +++++++++++++++++++++--
 b_asic/scheduler_gui/ui_main_window.py | 17 ++++++++++++++---
 5 files changed, 74 insertions(+), 7 deletions(-)

diff --git a/b_asic/GUI/main_window.py b/b_asic/GUI/main_window.py
index ded267a4..5daf997f 100644
--- a/b_asic/GUI/main_window.py
+++ b/b_asic/GUI/main_window.py
@@ -142,10 +142,12 @@ class SFGMainWindow(QMainWindow):
 
         self._ui.actionShowPC.triggered.connect(self._show_precedence_graph)
         self._ui.actionSimulateSFG.triggered.connect(self.simulate_sfg)
+        self._ui.actionSimulateSFG.setIcon(get_icon('sim'))
 
         # About menu
         self._ui.faqBASIC.triggered.connect(self.display_faq_page)
         self._ui.faqBASIC.setShortcut(QKeySequence("Ctrl+?"))
+        self._ui.faqBASIC.setIcon(get_icon('faq'))
         self._ui.aboutBASIC.triggered.connect(self.display_about_page)
         self._ui.aboutBASIC.setIcon(get_icon('about'))
         self._ui.keybindsBASIC.triggered.connect(self.display_keybindings_page)
@@ -175,7 +177,9 @@ class SFGMainWindow(QMainWindow):
         self._ui.exit_menu.setIcon(get_icon('quit'))
         self._ui.select_all.triggered.connect(self._select_all)
         self._ui.select_all.setShortcut(QKeySequence("Ctrl+A"))
+        self._ui.select_all.setIcon(get_icon('all'))
         self._ui.unselect_all.triggered.connect(self._unselect_all)
+        self._ui.unselect_all.setIcon(get_icon('none'))
         self._shortcut_signal = QShortcut(QKeySequence(Qt.Key_Space), self)
         self._shortcut_signal.activated.connect(self._connect_callback)
         self._create_recent_file_actions_and_menus()
@@ -202,6 +206,12 @@ class SFGMainWindow(QMainWindow):
         self._statusbar_visible.triggered.connect(self._toggle_statusbar)
         self._ui.view_menu.addAction(self._statusbar_visible)
 
+        # Zoom to fit
+        self._ui.view_menu.addSeparator()
+        self._zoom_to_fit_action = QAction(get_icon('zoom-to-fit'), "Zoom to &fit")
+        self._zoom_to_fit_action.triggered.connect(self._zoom_to_fit)
+        self._ui.view_menu.addAction(self._zoom_to_fit_action)
+
         # Non-modal dialogs
         self._keybindings_page = None
         self._about_page = None
@@ -411,7 +421,7 @@ class SFGMainWindow(QMainWindow):
 
         self._update_recent_file_list()
 
-    def exit_app(self) -> None:
+    def exit_app(self, event=None) -> None:
         """Exit the application."""
         self._logger.info("Exiting the application.")
         QApplication.quit()
@@ -869,6 +879,12 @@ class SFGMainWindow(QMainWindow):
             operation._toggle_button(pressed=True)
         self.update_statusbar("Unselected all operations")
 
+    def _zoom_to_fit(self, event=None):
+        """Callback for zoom to fit SFGs in window."""
+        self._graphics_view.fitInView(
+            self._scene.sceneRect(), Qt.AspectRatioMode.KeepAspectRatio
+        )
+
     def _simulate_sfg(self) -> None:
         """Callback for simulating SFGs in separate threads."""
         self._thread = dict()
diff --git a/b_asic/gui_utils/icons.py b/b_asic/gui_utils/icons.py
index f302345b..54f02db1 100644
--- a/b_asic/gui_utils/icons.py
+++ b/b_asic/gui_utils/icons.py
@@ -4,6 +4,7 @@ import qtawesome
 
 ICONS = {
     'save': 'mdi6.content-save',
+    'save-as': 'mdi6.content-save-edit',
     'undo': 'mdi6.undo',
     'redo': 'mdi6.redo',
     'new': 'mdi6.file-outline',
@@ -23,9 +24,16 @@ ICONS = {
     'about': 'ph.question',
     'keys': 'ph.keyboard',
     'add-operations': 'ph.math-operations',
+    'zoom-to-fit': 'mdi6.fit-to-page',
+    'faq': 'mdi6.frequently-asked-questions',
+    'sim': 'mdi6.chart-line',
+    'reorder': ('msc.graph-left', {'rotated': -90}),
 }
 
 
 def get_icon(name):
     """Return icon for given name"""
-    return qtawesome.icon(ICONS[name])
+    info = ICONS[name]
+    if isinstance(info, str):
+        return qtawesome.icon(info)
+    return qtawesome.icon(info[0], **info[1])
diff --git a/b_asic/scheduler_gui/main_window.py b/b_asic/scheduler_gui/main_window.py
index e35fc985..21f2b211 100644
--- a/b_asic/scheduler_gui/main_window.py
+++ b/b_asic/scheduler_gui/main_window.py
@@ -137,14 +137,19 @@ class ScheduleMainWindow(QMainWindow, Ui_MainWindow):
         self.menu_save.triggered.connect(self.save)
         self.menu_save.setIcon(get_icon('save'))
         self.menu_save_as.triggered.connect(self.save_as)
+        self.menu_save_as.setIcon(get_icon('save-as'))
         self.menu_quit.triggered.connect(self.close)
         self.menu_quit.setIcon(get_icon('quit'))
         self.menu_node_info.triggered.connect(self.show_info_table)
         self.menu_node_info.setIcon(get_icon('info'))
         self.menu_exit_dialog.triggered.connect(self.hide_exit_dialog)
         self.actionReorder.triggered.connect(self._action_reorder)
+        self.actionReorder.setIcon(get_icon('reorder'))
+        self.actionStatus_bar.triggered.connect(self._toggle_statusbar)
         self.actionPlot_schedule.triggered.connect(self._plot_schedule)
         self.actionPlot_schedule.setIcon(get_icon('plot-schedule'))
+        self.actionZoom_to_fit.triggered.connect(self._zoom_to_fit)
+        self.actionZoom_to_fit.setIcon(get_icon('zoom-to-fit'))
         self.actionUndo.setIcon(get_icon('undo'))
         self.actionRedo.setIcon(get_icon('redo'))
         self.splitter.splitterMoved.connect(self._splitter_moved)
@@ -741,6 +746,14 @@ class ScheduleMainWindow(QMainWindow, Ui_MainWindow):
 
         self._update_recent_file_list()
 
+    def _zoom_to_fit(self, event=None):
+        """Callback for zoom to fit schedule in window."""
+        self.view.fitInView(self._scene.sceneRect(), Qt.AspectRatioMode.KeepAspectRatio)
+
+    def _toggle_statusbar(self, event=None) -> None:
+        """Callback for toggling the status bar."""
+        self.statusbar.setVisible(self.actionStatus_bar.isChecked())
+
 
 def start_scheduler(schedule: Optional[Schedule] = None) -> Schedule:
     """
diff --git a/b_asic/scheduler_gui/main_window.ui b/b_asic/scheduler_gui/main_window.ui
index 1c55fbe0..4eb76195 100644
--- a/b_asic/scheduler_gui/main_window.ui
+++ b/b_asic/scheduler_gui/main_window.ui
@@ -92,7 +92,7 @@
         <bool>false</bool>
        </attribute>
        <attribute name="verticalHeaderDefaultSectionSize">
-        <number>19</number>
+        <number>24</number>
        </attribute>
        <row>
         <property name="text">
@@ -202,7 +202,7 @@
      <x>0</x>
      <y>0</y>
      <width>800</width>
-     <height>20</height>
+     <height>22</height>
     </rect>
    </property>
    <widget class="QMenu" name="menuFile">
@@ -228,8 +228,11 @@
      <string>&amp;View</string>
     </property>
     <addaction name="menu_node_info"/>
+    <addaction name="actionStatus_bar"/>
     <addaction name="separator"/>
     <addaction name="actionPlot_schedule"/>
+    <addaction name="separator"/>
+    <addaction name="actionZoom_to_fit"/>
    </widget>
    <widget class="QMenu" name="menu_Edit">
     <property name="title">
@@ -445,6 +448,22 @@
     <string>Decrease time resolution...</string>
    </property>
   </action>
+  <action name="actionZoom_to_fit">
+   <property name="text">
+    <string>Zoom to fit</string>
+   </property>
+  </action>
+  <action name="actionStatus_bar">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="checked">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Status bar</string>
+   </property>
+  </action>
  </widget>
  <resources/>
  <connections/>
diff --git a/b_asic/scheduler_gui/ui_main_window.py b/b_asic/scheduler_gui/ui_main_window.py
index 220bdec5..4cf895d6 100644
--- a/b_asic/scheduler_gui/ui_main_window.py
+++ b/b_asic/scheduler_gui/ui_main_window.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 
-# Form implementation generated from reading ui file './main_window.ui'
+# Form implementation generated from reading ui file '.\main_window.ui'
 #
 # Created by: PyQt5 UI code generator 5.15.7
 #
@@ -123,11 +123,11 @@ class Ui_MainWindow(object):
         self.info_table.horizontalHeader().setHighlightSections(False)
         self.info_table.horizontalHeader().setStretchLastSection(True)
         self.info_table.verticalHeader().setVisible(False)
-        self.info_table.verticalHeader().setDefaultSectionSize(19)
+        self.info_table.verticalHeader().setDefaultSectionSize(24)
         self.horizontalLayout.addWidget(self.splitter)
         MainWindow.setCentralWidget(self.centralwidget)
         self.menubar = QtWidgets.QMenuBar(MainWindow)
-        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 20))
+        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
         self.menubar.setObjectName("menubar")
         self.menuFile = QtWidgets.QMenu(self.menubar)
         self.menuFile.setObjectName("menuFile")
@@ -218,6 +218,12 @@ class Ui_MainWindow(object):
         self.actionDecrease_time_resolution.setObjectName(
             "actionDecrease_time_resolution"
         )
+        self.actionZoom_to_fit = QtWidgets.QAction(MainWindow)
+        self.actionZoom_to_fit.setObjectName("actionZoom_to_fit")
+        self.actionStatus_bar = QtWidgets.QAction(MainWindow)
+        self.actionStatus_bar.setCheckable(True)
+        self.actionStatus_bar.setChecked(True)
+        self.actionStatus_bar.setObjectName("actionStatus_bar")
         self.menuFile.addAction(self.menu_load_from_file)
         self.menuFile.addAction(self.menu_close_schedule)
         self.menuFile.addAction(self.menu_save)
@@ -227,8 +233,11 @@ class Ui_MainWindow(object):
         self.menuFile.addSeparator()
         self.menuFile.addAction(self.menu_quit)
         self.menuView.addAction(self.menu_node_info)
+        self.menuView.addAction(self.actionStatus_bar)
         self.menuView.addSeparator()
         self.menuView.addAction(self.actionPlot_schedule)
+        self.menuView.addSeparator()
+        self.menuView.addAction(self.actionZoom_to_fit)
         self.menu_Edit.addAction(self.actionUndo)
         self.menu_Edit.addAction(self.actionRedo)
         self.menu_Edit.addSeparator()
@@ -314,3 +323,5 @@ class Ui_MainWindow(object):
         self.actionDecrease_time_resolution.setText(
             _translate("MainWindow", "Decrease time resolution...")
         )
+        self.actionZoom_to_fit.setText(_translate("MainWindow", "Zoom to fit"))
+        self.actionStatus_bar.setText(_translate("MainWindow", "Status bar"))
-- 
GitLab