Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions trace/assets/dark_icons/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions trace/assets/dark_icons/circle-solid.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions trace/assets/dark_icons/down-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions trace/assets/dark_icons/left-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions trace/assets/dark_icons/right-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions trace/assets/dark_icons/up-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions trace/assets/light_icons/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions trace/assets/light_icons/circle-solid.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions trace/assets/light_icons/down-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions trace/assets/light_icons/left-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions trace/assets/light_icons/right-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions trace/assets/light_icons/up-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions trace/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
with config_file.open() as f:
loaded_json = load(f)

light_stylesheet = Path(__file__).parent / "stylesheets/light_mode.qss"
dark_stylesheet = Path(__file__).parent / "stylesheets/dark_mode.qss"

logger = getLogger("")

datetime_pv = loaded_json["datetime_pv"]
Expand Down
113 changes: 83 additions & 30 deletions trace/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
from getpass import getuser
from datetime import datetime

import qtawesome as qta
from qtpy.QtGui import QFont, QImage, QKeySequence
from qtpy.QtCore import Qt, Slot, QSize, Signal, QBuffer, QIODevice
from qtpy.QtGui import QFont, QColor, QImage, QKeySequence
from qtpy.QtCore import Qt, Slot, QSize, Signal, QBuffer, QIODevice, QSettings
from qtpy.QtWidgets import (
QMenu,
QLabel,
Expand All @@ -24,9 +23,11 @@
QVBoxLayout,
QApplication,
QButtonGroup,
QAbstractButton,
)
from pyqtgraph.exporters import ImageExporter
from services.elog_client import get_user, post_entry
from services.theme_manager import Theme, IconColors, ThemeManager

from pydm import Display
from pydm.widgets import PyDMLabel, PyDMArchiverTimePlot
Expand All @@ -46,8 +47,19 @@ class TraceDisplay(Display):

def __init__(self, parent=None, args=None, macros=None) -> None:
super(TraceDisplay, self).__init__(parent=parent, args=args, macros=macros, ui_filename=None)

app = QApplication.instance()
if not app.main_window:
return

self.theme_manager = ThemeManager(
app,
)
settings = QSettings()
self.is_dark_mode = settings.value("isDarkTheme", False, type=bool)
self.build_ui()
self.configure_app()
self.configure_app(app)
self.setup_icons()
self.resize(1000, 600)

# Set plot's timerange after the UI is built
Expand Down Expand Up @@ -77,7 +89,7 @@ def build_ui(self) -> None:

# Create the plotting and control widgets
plot_side_widget = self.build_plot_side(self)
self.control_panel = ControlPanel()
self.control_panel = ControlPanel(theme_manager=self.theme_manager)
self.control_panel.layout().setContentsMargins(8, 0, 0, 0)
self.control_panel.plot = self.plot
self.control_panel.curve_list_changed.connect(self.data_insight_tool.update_pv_select_box)
Expand All @@ -89,15 +101,7 @@ def build_ui(self) -> None:
main_splitter.setCollapsible(0, False)
main_splitter.setStretchFactor(0, 1)
main_splitter.setHandleWidth(10)
main_splitter.setStyleSheet(
"\n".join(
[
"QSplitter::handle {",
" background-color: white;",
"}",
]
)
)

main_layout.addWidget(main_splitter)

# Create the footer section of the app
Expand All @@ -113,10 +117,11 @@ def build_plot_side(self, parent):
toolbar = self.build_toolbar(plot_side_widget)
plot_side_layout.addWidget(toolbar)

# Create plot
background_color = "#1E1E1E" if self.theme_manager.get_current_theme() == Theme.DARK else "white"

self.plot = PyDMArchiverTimePlot(
plot_side_widget,
background="white",
background=background_color,
optimized_data_bins=5000,
cache_data=False,
show_all=False,
Expand All @@ -131,7 +136,6 @@ def build_plot_side(self, parent):
self.data_insight_tool.plot = self.plot

self.settings_button = QPushButton(self.plot)
self.settings_button.setIcon(qta.icon("msc.settings-gear"))
self.settings_button.setFlat(True)

self.plot_settings = PlotSettingsModal(self.settings_button, self.plot)
Expand Down Expand Up @@ -246,12 +250,28 @@ def set_file_indicator(self, file_path: str) -> None:
self.file_label.setToolTip("Currently loaded file")
self.footer_info_widget.layout().addWidget(self.file_label)

def configure_app(self):
"""UI changes to be made to the PyDMApplication"""
app = QApplication.instance()
if not app.main_window:
return
def setup_icons(self):
"""Set up all icons after theme manager is initialized"""
self.settings_button.setIcon(self.theme_manager.create_icon("msc.settings-gear", IconColors.PRIMARY))

def on_theme_changed(self, theme: Theme):
"""Handle theme changes - update icons and button text"""
if theme == Theme.DARK:
self.theme_toggle_button.setText("Light Mode")
icon = self.theme_manager.create_icon("fa.sun-o", IconColors.PRIMARY)
else:
self.theme_toggle_button.setText("Dark Mode")
icon = self.theme_manager.create_icon("fa.moon-o", IconColors.PRIMARY)

if icon:
self.theme_toggle_button.setIcon(icon)

settings_icon = self.theme_manager.create_icon("msc.settings-gear", IconColors.PRIMARY)
if settings_icon:
self.settings_button.setIcon(settings_icon)

def configure_app(self, app):
"""UI changes to be made to the PyDMApplication"""
# Hide navigation bar by default (can be shown in menu bar)
app.main_window.toggle_nav_bar(False)
app.main_window.ui.actionShow_Navigation_Bar.setChecked(False)
Expand Down Expand Up @@ -302,8 +322,35 @@ def construct_trace_menu(self, parent: QMenuBar) -> QMenu:
dit_action = menu.addAction("Data Insight Tool...", self.data_insight_tool.show)
dit_action.setShortcut(QKeySequence("Ctrl+D"))

menu.addSeparator()

if self.is_dark_mode:
self.theme_action = menu.addAction("Switch to Light Mode", self.toggle_theme)
else:
self.theme_action = menu.addAction("Switch to Dark Mode", self.toggle_theme)

self.theme_action.setShortcut(QKeySequence("Ctrl+T"))

return menu

def toggle_theme(self):
"""Toggle between dark and light mode."""
if self.is_dark_mode:
self.theme_manager.set_theme(Theme.LIGHT)
self.theme_action.setText("Switch to Dark Mode")
self.plot.setBackgroundColor(QColor("#FFFFFF"))
self.setup_icons()
self.is_dark_mode = False
else:
self.theme_manager.set_theme(Theme.DARK)
self.theme_action.setText("Switch to Light Mode")
self.plot.setBackgroundColor(QColor("#1E1E1E"))
self.setup_icons()
self.is_dark_mode = True

QApplication.processEvents()
self.repaint()

@Slot()
def save_plot_image(self) -> None:
"""Saves current plot as an image. Opens file dialog to allow user to
Expand Down Expand Up @@ -408,23 +455,29 @@ def set_plot_timerange(self, timerange: tuple[float, float]) -> None:

@Slot()
@Slot(float)
def set_auto_scroll_span(self, timespan: float = None) -> None:
@Slot(QAbstractButton, float)
def set_auto_scroll_span(self, arg1=None, arg2=None) -> None:
"""Slot to be called when a timespan setting button is pressed.
This will enable autoscrolling along the x-axis and disable mouse
controls. If the "Cursor" button is pressed, then autoscrolling is
disabled and mouse controls are enabled.
"""
if timespan is None:
timespan = self.timespan_buttons.checkedId()
enable_scroll = timespan != DISABLE_AUTO_SCROLL
disabled and mouse controls are enabled."""
if isinstance(arg1, QAbstractButton):
if not arg2:
return
timespan = self.timespan_buttons.id(arg1)
elif isinstance(arg1, (int, float)):
timespan = arg1
else:
enable_scroll = True
self.disable_auto_scroll_button.click()
timespan = self.timespan_buttons.checkedId()

enable_scroll = timespan != DISABLE_AUTO_SCROLL

if enable_scroll:
logger.debug(f"Enabling plot autoscroll for {timespan}s")
else:
logger.debug("Disabling plot autoscroll, using mouse controls")
self.disable_auto_scroll_button.click()

self.autoScroll(enable=enable_scroll, timespan=timespan)

@Slot(int)
Expand Down
Loading
Loading