diff --git a/src/surface/gui/gui/app.py b/src/surface/gui/gui/app.py index f800e24a..cc5ef2ce 100644 --- a/src/surface/gui/gui/app.py +++ b/src/surface/gui/gui/app.py @@ -1,9 +1,12 @@ import atexit import signal +from pathlib import Path from threading import Thread import rclpy.utilities +from ament_index_python import get_package_share_directory from PyQt6.QtWidgets import QApplication, QWidget +from qt_material import apply_stylesheet from rclpy.executors import MultiThreadedExecutor from gui.gui_node import GUINode @@ -29,18 +32,27 @@ def run_gui(self) -> None: # Kills with Control + C signal.signal(signal.SIGINT, signal.SIG_DFL) - # TODO: New method of dark mode + extra_blue = {'success': '#040444', 'danger': '#040444', 'warning': '#040444'} + extra_watermelon = {'success': '#341616', 'danger': '#341616', 'warning': '#341616'} # Apply theme - # theme_param = self.theme_param.get_parameter_value().string_value - # theme_path = Path(get_package_share_directory('gui')) / 'styles' / (theme_param + '.qss') - - # base_theme = 'dark' if theme_param == 'dark' else 'light' - # custom_styles = '\n' - # if theme_path.exists(): - # with theme_path.open(encoding='utf-8') as theme_file: - # custom_styles += theme_file.read() - - # qdarktheme.setup_theme(base_theme, additional_qss=custom_styles) + theme_param = self.theme_param.get_parameter_value().string_value + + match theme_param: + case 'dark': + base_theme = 'dark_blue.xml' + case 'light': + base_theme = 'light_blue.xml' + case 'watermelon': + base_path = Path(get_package_share_directory('gui')) / 'styles' / ('watermelon.xml') + base_theme = base_path.as_posix() + case _: + base_theme = 'dark_blue.xml' + self.node.get_logger().info( + 'Theme ' + theme_param + ' not found, defaulting to dark.' + ) + + extra = extra_watermelon if theme_param == 'watermelon' else extra_blue + apply_stylesheet(self, theme=base_theme, style='', extra=extra) executor = MultiThreadedExecutor() executor.add_node(self.node) diff --git a/src/surface/gui/gui/styles/custom_styles.py b/src/surface/gui/gui/styles/custom_styles.py index aa034175..bfb59198 100644 --- a/src/surface/gui/gui/styles/custom_styles.py +++ b/src/surface/gui/gui/styles/custom_styles.py @@ -15,10 +15,16 @@ class IndicatorMixin(QWidget): # The stylesheets that correspond to each widget state _STYLESHEETS: Final[dict[WidgetState, str]] = { # Stylesheet for when a component is running, enabled, or armed - WidgetState.ON: 'QWidget { background-color: limegreen; }', + WidgetState.ON: """ + QWidget { background-color: limegreen; } + QWidget:hover { background-color: #5bd75b; } + """, # Stylesheet for when a component is disabled, not running, or disarmed, but could be # enabled through this widget - WidgetState.OFF: 'QWidget { background-color: red; }', + WidgetState.OFF: """ + QWidget { background-color: red; } + QWidget:hover { background-color: #ff3333; } + """, # Stylesheet for when a component is disabled, not expected to have any effect or perform # its function because of some external factor, either another widget or something # external to the gui. For example, a the arm button when the pi is not connected @@ -48,6 +54,13 @@ def set_state(self, new_state: WidgetState) -> None: The new state for the widget """ self.current_state = new_state + match self.current_state: + case WidgetState.OFF: + self.setProperty('class', 'danger') + case WidgetState.ON: + self.setProperty('class', 'success') + case _: + self.setProperty('class', 'warning') self.setStyleSheet(self._original_stylesheet + self._STYLESHEETS[self.current_state]) diff --git a/src/surface/gui/gui/styles/watermelon.xml b/src/surface/gui/gui/styles/watermelon.xml new file mode 100644 index 00000000..238ca8e8 --- /dev/null +++ b/src/surface/gui/gui/styles/watermelon.xml @@ -0,0 +1,10 @@ + + + #ff4d4e + #bf0002 + #6f0001 + #31363b + #1b5e1a + #ffffff + #ffffff + \ No newline at end of file diff --git a/src/surface/gui/package.xml b/src/surface/gui/package.xml index a89af075..54d33fa1 100644 --- a/src/surface/gui/package.xml +++ b/src/surface/gui/package.xml @@ -13,6 +13,7 @@ python3-numpy cv_bridge + python3-qt-material-pip python3-pyqtgraph pyqt6-dev-tools python3-pyqt6.qtmultimedia diff --git a/src/surface/gui/setup.py b/src/surface/gui/setup.py index 46a75c5f..ca253db3 100644 --- a/src/surface/gui/setup.py +++ b/src/surface/gui/setup.py @@ -27,7 +27,7 @@ # Include all style files. ( str(Path('share') / PACKAGE_NAME / 'styles'), - [str(path) for path in (Path('gui') / 'styles').glob('*.qss')], + [str(path) for path in (Path('gui') / 'styles').glob('*.xml')], ), # Include all images. (