diff --git a/doc/changelog.d/228.added.md b/doc/changelog.d/228.added.md new file mode 100644 index 00000000..c6d1aa51 --- /dev/null +++ b/doc/changelog.d/228.added.md @@ -0,0 +1 @@ +feat: Add dark mode when background is dark \ No newline at end of file diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/pyvista.py b/src/ansys/tools/visualization_interface/backends/pyvista/pyvista.py index f7f4bed4..6ba05bbd 100644 --- a/src/ansys/tools/visualization_interface/backends/pyvista/pyvista.py +++ b/src/ansys/tools/visualization_interface/backends/pyvista/pyvista.py @@ -55,6 +55,8 @@ _HAS_TRAME = importlib.util.find_spec("pyvista.trame") and importlib.util.find_spec("trame.app") +DARK_MODE_THRESHOLD = 120 + if TYPE_CHECKING: import numpy as np @@ -179,25 +181,31 @@ def scene(self) -> pv.Plotter: """PyVista scene.""" return self._pl.scene - def enable_widgets(self): - """Enable the widgets for the plotter.""" + def enable_widgets(self, dark_mode: bool = False) -> None: + """Enable the widgets for the plotter. + + Parameters + ---------- + dark_mode : bool, default: False + Whether to use dark mode for the widgets. + """ # Create Plotter widgets if self._enable_widgets: self._widgets: List[PlotterWidget] = [] - self._widgets.append(Ruler(self._pl._scene)) + self._widgets.append(Ruler(self._pl._scene, dark_mode)) [ - self._widgets.append(DisplacementArrow(self._pl._scene, direction=dir)) + self._widgets.append(DisplacementArrow(self._pl._scene, dir, dark_mode)) for dir in CameraPanDirection ] [ - self._widgets.append(ViewButton(self._pl._scene, direction=dir)) + self._widgets.append(ViewButton(self._pl._scene, dir, dark_mode)) for dir in ViewDirection ] - self._widgets.append(MeasureWidget(self)) - self._widgets.append(ScreenshotButton(self)) + self._widgets.append(MeasureWidget(self, dark_mode)) + self._widgets.append(ScreenshotButton(self, dark_mode)) if not self._use_qt: - self._widgets.append(MeshSliderWidget(self)) - self._widgets.append(HideButton(self)) + self._widgets.append(MeshSliderWidget(self, dark_mode)) + self._widgets.append(HideButton(self, dark_mode)) def add_widget(self, widget: Union[PlotterWidget, List[PlotterWidget]]): """Add one or more custom widgets to the plotter. @@ -403,6 +411,7 @@ def show( screenshot: Optional[str] = None, view_2d: Dict = None, name_filter: str = None, + dark_mode: bool = False, **plotting_options, ) -> List[Any]: """Plot and show any PyAnsys object. @@ -420,6 +429,8 @@ def show( Dictionary with the plane and the viewup vectors of the 2D plane. name_filter : str, default: None Regular expression with the desired name or names to include in the plotter. + dark_mode : bool, default: False + Whether to use dark mode for the widgets. **plotting_options : dict, default: None Keyword arguments. For allowable keyword arguments, see the :meth:`Plotter.add_mesh ` method. @@ -446,7 +457,16 @@ def show( ) # Enable widgets and picking capabilities if screenshot is None and not ansys.tools.visualization_interface.DOCUMENTATION_BUILD: - self.enable_widgets() + if dark_mode: + self.enable_widgets(dark_mode=dark_mode) + elif all([ + color < DARK_MODE_THRESHOLD + for color in self._pl.scene.background_color.int_rgb + ]): + print([color for color in self._pl.scene.background_color.int_rgb]) + self.enable_widgets(dark_mode=True) + else: + self.enable_widgets() if self._allow_picking: self.enable_picking() diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+xy_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+xy_inv.png new file mode 100644 index 00000000..1d507c49 Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+xy_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+xz_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+xz_inv.png new file mode 100644 index 00000000..def750ae Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+xz_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+yz_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+yz_inv.png new file mode 100644 index 00000000..5d6fa017 Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+yz_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-xy_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-xy_inv.png new file mode 100644 index 00000000..2b49d311 Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-xy_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-xz_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-xz_inv.png new file mode 100644 index 00000000..661872e8 Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-xz_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-yz_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-yz_inv.png new file mode 100644 index 00000000..f05eaf5c Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-yz_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/designpoint.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/designpoint.png deleted file mode 100644 index e5c8af54..00000000 Binary files a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/designpoint.png and /dev/null differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/downarrow_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/downarrow_inv.png new file mode 100644 index 00000000..2d0629a5 Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/downarrow_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/isometric_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/isometric_inv.png new file mode 100644 index 00000000..477d4a2b Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/isometric_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/measurement_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/measurement_inv.png new file mode 100644 index 00000000..5505dfe2 Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/measurement_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/planecut_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/planecut_inv.png new file mode 100644 index 00000000..9c2d35fe Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/planecut_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/ruler_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/ruler_inv.png new file mode 100644 index 00000000..17083987 Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/ruler_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/screenshot_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/screenshot_inv.png new file mode 100644 index 00000000..8ea47d8e Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/screenshot_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upxarrow_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upxarrow_inv.png new file mode 100644 index 00000000..0f8efe5d Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upxarrow_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upyarrow_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upyarrow_inv.png new file mode 100644 index 00000000..ff8cd140 Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upyarrow_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upzarrow_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upzarrow_inv.png new file mode 100644 index 00000000..d419ae53 Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upzarrow_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/visibilityoff_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/visibilityoff_inv.png new file mode 100644 index 00000000..9298a1d7 Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/visibilityoff_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/visibilityon_inv.png b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/visibilityon_inv.png new file mode 100644 index 00000000..6e9fb9cf Binary files /dev/null and b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/_images/visibilityon_inv.png differ diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/button.py b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/button.py index 93a0ff85..b506c896 100644 --- a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/button.py +++ b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/button.py @@ -43,12 +43,15 @@ class Button(PlotterWidget): Plotter to draw the buttons on. button_config : tuple Tuple containing the position and the path to the icon of the button. + dark_mode : bool, optional + Whether to activate the dark mode or not. """ - def __init__(self, plotter: Plotter, button_config: tuple): + def __init__(self, plotter: Plotter, button_config: tuple, dark_mode: bool = False) -> None: """Initialize the ``Button`` class.""" super().__init__(plotter) + self._dark_mode = dark_mode self._button: vtkButtonWidget = self.plotter.add_checkbox_button_widget( self.callback, position=button_config.value[2], size=30, border_size=3 ) @@ -68,9 +71,13 @@ def callback(self, state: bool) -> None: def update(self) -> None: """Assign the image that represents the button.""" + if self._dark_mode: + is_inv = "_inv" + else: + is_inv = "" button_repr = self._button.GetRepresentation() button_icon_path = Path( - Path(__file__).parent / "_images", self.button_config.value[1] + Path(__file__).parent / "_images", f"{self.button_config.value[1]}{is_inv}.png" ) button_icon = vtkPNGReader() button_icon.SetFileName(button_icon_path) diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/displace_arrows.py b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/displace_arrows.py index 6f74b37b..e8b6d50e 100644 --- a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/displace_arrows.py +++ b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/displace_arrows.py @@ -30,12 +30,12 @@ class CameraPanDirection(Enum): """Provides an enum with the available movement directions of the camera.""" - XUP = 0, "upxarrow.png", (5, 170) - XDOWN = 1, "downarrow.png", (5, 130) - YUP = 2, "upyarrow.png", (35, 170) - YDOWN = 3, "downarrow.png", (35, 130) - ZUP = 4, "upzarrow.png", (65, 170) - ZDOWN = 5, "downarrow.png", (65, 130) + XUP = 0, "upxarrow", (5, 170) + XDOWN = 1, "downarrow", (5, 130) + YUP = 2, "upyarrow", (35, 170) + YDOWN = 3, "downarrow", (35, 130) + ZUP = 4, "upzarrow", (65, 170) + ZDOWN = 5, "downarrow", (65, 130) class DisplacementArrow(Button): @@ -47,12 +47,13 @@ class DisplacementArrow(Button): Plotter to draw the buttons on. direction : CameraPanDirection Direction that the camera is to move. - + dark_mode : bool, optional + Whether to activate the dark mode or not. """ - def __init__(self, plotter: Plotter, direction: CameraPanDirection): + def __init__(self, plotter: Plotter, direction: CameraPanDirection, dark_mode: bool = False) -> None: """Initialize the ``DisplacementArrow`` class.""" - super().__init__(plotter, direction) + super().__init__(plotter, direction, dark_mode) self.direction = direction self.update() diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/hide_buttons.py b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/hide_buttons.py index 4d955bb5..360f9a9c 100644 --- a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/hide_buttons.py +++ b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/hide_buttons.py @@ -38,14 +38,16 @@ class HideButton(PlotterWidget): ---------- plotter_helper : PlotterHelper Plotter to add the hide widget to. + dark_mode : bool, optional + Whether to activate the dark mode or not. """ - def __init__(self, plotter: "Plotter") -> None: + def __init__(self, plotter: "Plotter", dark_mode: bool = False) -> None: """Initialize the ``HideButton`` class.""" # Call PlotterWidget ctor super().__init__(plotter._pl.scene) - + self._dark_mode = dark_mode # Initialize variables self._actor: vtkActor = None self._plotter = plotter @@ -70,17 +72,22 @@ def callback(self, state: bool) -> None: widget._button.GetRepresentation().SetVisibility(0) else: for widget in self.plotter._widgets: - widget._button.On() - widget._button.GetRepresentation().SetVisibility(1) + widget._button.On() + widget._button.GetRepresentation().SetVisibility(1) def update(self) -> None: """Define the hide widget button parameters.""" + if self._dark_mode: + is_inv = "_inv" + else: + is_inv = "" + show_vr = self._button.GetRepresentation() show_vison_icon_file = Path( - Path(__file__).parent / "_images"/ "visibilityon.png" + Path(__file__).parent / "_images" / f"visibilityon{is_inv}.png" ) show_visoff_icon_file = Path( - Path(__file__).parent / "_images"/ "visibilityoff.png" + Path(__file__).parent / "_images" / f"visibilityon{is_inv}.png" ) show_r_on = vtkPNGReader() show_r_on.SetFileName(show_vison_icon_file) diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/measure.py b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/measure.py index eedea2a8..dbf2a0c3 100644 --- a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/measure.py +++ b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/measure.py @@ -38,14 +38,16 @@ class MeasureWidget(PlotterWidget): ---------- plotter_helper : PlotterHelper Plotter to add the measure widget to. + dark_mode : bool, optional + Whether to activate the dark mode or not. """ - def __init__(self, plotter_helper: "Plotter") -> None: + def __init__(self, plotter_helper: "Plotter", dark_mode: bool = False) -> None: """Initialize the ``MeasureWidget`` class.""" # Call PlotterWidget ctor super().__init__(plotter_helper._pl.scene) - + self._dark_mode = dark_mode # Initialize variables self._actor: vtkActor = None self.plotter_helper = plotter_helper @@ -84,9 +86,13 @@ def callback(self, state: bool) -> None: def update(self) -> None: """Define the measurement widget button parameters.""" + if self._dark_mode: + is_inv = "_inv" + else: + is_inv = "" show_measure_vr = self._button.GetRepresentation() show_measure_icon_file = Path( - Path(__file__).parent / "_images"/ "measurement.png" + Path(__file__).parent / "_images" / f"measurement{is_inv}.png" ) show_measure_r = vtkPNGReader() show_measure_r.SetFileName(show_measure_icon_file) diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/mesh_slider.py b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/mesh_slider.py index b22d1469..11c26d1b 100644 --- a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/mesh_slider.py +++ b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/mesh_slider.py @@ -38,14 +38,16 @@ class MeshSliderWidget(PlotterWidget): ---------- plotter_helper : PlotterHelper Plotter to add the mesh slider widget to. + dark_mode : bool, optional + Whether to activate the dark mode or not. """ - def __init__(self, plotter_helper: "Plotter") -> None: + def __init__(self, plotter_helper: "Plotter", dark_mode: bool = False) -> None: """Initialize the ``MeshSliderWidget`` class.""" # Call PlotterWidget ctor super().__init__(plotter_helper._pl.scene) - + self._dark_mode = dark_mode # Initialize variables self._widget_actor: vtkActor = None self.plotter_helper = plotter_helper @@ -101,9 +103,13 @@ def callback(self, state: bool) -> None: def update(self) -> None: """Define the mesh slider widget button parameters.""" + if self._dark_mode: + is_inv = "_inv" + else: + is_inv = "" show_measure_vr = self._button.GetRepresentation() show_measure_icon_file = Path( - Path(__file__).parent / "_images"/ "planecut.png" + Path(__file__).parent / "_images" / f"planecut{is_inv}.png" ) show_measure_r = vtkPNGReader() show_measure_r.SetFileName(show_measure_icon_file) diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/ruler.py b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/ruler.py index d6caf0ef..9effb7a4 100644 --- a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/ruler.py +++ b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/ruler.py @@ -36,14 +36,16 @@ class Ruler(PlotterWidget): ---------- plotter : ~pyvista.Plotter Provides the plotter to add the ruler widget to. + dark_mode : bool, optional + Whether to activate the dark mode or not. """ - def __init__(self, plotter: Plotter) -> None: + def __init__(self, plotter: Plotter, dark_mode: bool = False) -> None: """Initialize the ``Ruler`` class.""" # Call PlotterWidget ctor super().__init__(plotter) - + self._dark_mode = dark_mode # Initialize variables self._actor: vtkActor = None self._button: vtkButtonWidget = self.plotter.add_checkbox_button_widget( @@ -76,7 +78,7 @@ def callback(self, state: bool) -> None: show_xaxis=True, show_yaxis=True, show_zaxis=True, - color="black", + color="white" if self._dark_mode else "black", xtitle="X Axis [m]", ytitle="Y Axis [m]", ztitle="Z Axis [m]", @@ -84,8 +86,12 @@ def callback(self, state: bool) -> None: def update(self) -> None: """Define the configuration and representation of the ruler widget button.""" + if self._dark_mode: + is_inv = "_inv" + else: + is_inv = "" show_ruler_vr = self._button.GetRepresentation() - show_ruler_icon_file = Path(Path(__file__).parent / "_images" / "ruler.png") + show_ruler_icon_file = Path(Path(__file__).parent / "_images" / f"ruler{is_inv}.png") show_ruler_r = vtkPNGReader() show_ruler_r.SetFileName(show_ruler_icon_file) show_ruler_r.Update() diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/screenshot.py b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/screenshot.py index 46e4674c..b6a5a846 100644 --- a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/screenshot.py +++ b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/screenshot.py @@ -36,14 +36,16 @@ class ScreenshotButton(PlotterWidget): ---------- plotter : ~pyvista.Plotter Provides the plotter to add the screenshot widget to. + dark_mode : bool, optional + Whether to activate the dark mode or not. """ - def __init__(self, plotter: Plotter) -> None: + def __init__(self, plotter: Plotter, dark_mode: bool = False) -> None: """Initialize the ``ScreenshotButton`` class.""" # Call PlotterWidget ctor super().__init__(plotter) - + self._dark_mode = dark_mode # Initialize variables self._actor: vtkActor = None self._button: vtkButtonWidget = self.plotter._pl.scene.add_checkbox_button_widget( @@ -69,8 +71,12 @@ def callback(self, state: bool) -> None: def update(self) -> None: """Define the configuration and representation of the screenshot widget button.""" + if self._dark_mode: + is_inv = "_inv" + else: + is_inv = "" show_vr = self._button.GetRepresentation() - show_icon_file = Path(Path(__file__).parent / "_images" / "screenshot.png") + show_icon_file = Path(Path(__file__).parent / "_images" / f"screenshot{is_inv}.png") show_r = vtkPNGReader() show_r.SetFileName(show_icon_file) show_r.Update() diff --git a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/view_button.py b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/view_button.py index a3f31242..a8e040c9 100644 --- a/src/ansys/tools/visualization_interface/backends/pyvista/widgets/view_button.py +++ b/src/ansys/tools/visualization_interface/backends/pyvista/widgets/view_button.py @@ -31,13 +31,13 @@ class ViewDirection(Enum): """Provides an enum with the available views.""" - XYPLUS = 0, "+xy.png", (5, 220) - XYMINUS = 1, "-xy.png", (5, 251) - XZPLUS = 2, "+xz.png", (5, 282) - XZMINUS = 3, "-xz.png", (5, 313) - YZPLUS = 4, "+yz.png", (5, 344) - YZMINUS = 5, "-yz.png", (5, 375) - ISOMETRIC = 6, "isometric.png", (5, 406) + XYPLUS = 0, "+xy", (5, 220) + XYMINUS = 1, "-xy", (5, 251) + XZPLUS = 2, "+xz", (5, 282) + XZMINUS = 3, "-xz", (5, 313) + YZPLUS = 4, "+yz", (5, 344) + YZMINUS = 5, "-yz", (5, 375) + ISOMETRIC = 6, "isometric", (5, 406) class ViewButton(Button): @@ -49,12 +49,13 @@ class ViewButton(Button): Plotter to draw the buttons on. direction : ViewDirection Direction of the view. - + dark_mode : bool, optional + Whether to activate the dark mode or not. """ - def __init__(self, plotter: Plotter, direction: tuple): + def __init__(self, plotter: Plotter, direction: tuple, dark_mode: bool = False) -> None: """Initialize the ``ViewButton`` class.""" - super().__init__(plotter, direction) + super().__init__(plotter, direction, dark_mode) self.direction = direction self.update()