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
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pydm
numpy
pandas
scipy
pytest
pytest-qt
qtawesome
Expand Down
28 changes: 24 additions & 4 deletions trace/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
QAbstractButton,
)
from pyqtgraph.exporters import ImageExporter
from pyqtgraph.graphicsItems.LegendItem import ItemSample

from pydm import Display
from pydm.widgets import PyDMLabel, PyDMArchiverTimePlot
Expand All @@ -41,6 +42,17 @@
DISABLE_AUTO_SCROLL = -2 # Using -2 as invalid since QButtonGroups use -1 as invalid


class _LegendSample(ItemSample):
"""Legend sample that does not toggle curve visibility on click.

Trace manages curve visibility through the control panel toggles,
so legend clicks should not independently change visibility state.
"""

def mouseClickEvent(self, event):
event.accept()


class TraceDisplay(Display):
"""Main display widget for the Trace application.

Expand Down Expand Up @@ -183,6 +195,7 @@ def build_plot_side(self, parent: QWidget) -> QWidget:
cache_data=False,
show_all=False,
)
self.plot._legend.sampleType = _LegendSample

multi_axis_plot = self.plot.plotItem
multi_axis_plot.vb.menu = None
Expand Down Expand Up @@ -785,10 +798,17 @@ def git_version():
The output of `git describe --tags`, or an empty string on failure.
"""
project_directory = __file__.rsplit("/", 1)[0]
git_cmd = subprocess.run(
f"cd {project_directory} && git describe --tags", text=True, shell=True, capture_output=True
)
return git_cmd.stdout.strip()
try:
git_cmd = subprocess.run(
f"cd {project_directory} && git describe --tags",
text=True,
shell=True,
capture_output=True,
timeout=5,
)
return git_cmd.stdout.strip()
except subprocess.TimeoutExpired:
return ""

def parse_cli_args(self, args, macros):
"""Parse CLI-style arguments and macros into startup configuration.
Expand Down
3 changes: 3 additions & 0 deletions trace/services/theme_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

from config import dark_stylesheet, light_stylesheet

ASSETS_DIR = str(light_stylesheet.parent.parent / "assets")

type ColorHex = str
type IconColorDict = dict[str, ColorHex]
type ButtonIconInfo = tuple[str, QPushButton, str, str]
Expand Down Expand Up @@ -192,6 +194,7 @@ def set_theme(self, theme: Theme) -> None:
self.app.setPalette(self.light_palette)
stylesheet = light_stylesheet.read_text()

stylesheet = stylesheet.replace('url("assets/', f'url("{ASSETS_DIR}/')
Comment thread
YektaY marked this conversation as resolved.
self.app.main_window.setStyleSheet(stylesheet)

settings = QSettings()
Expand Down
2 changes: 1 addition & 1 deletion trace/stylesheets/light_mode.qss
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ QCheckBox {
}

QCheckBox::indicator:unchecked {
background-color: #2A2A2A;
background-color: #FFFFFF;
Comment thread
YektaY marked this conversation as resolved.
}

QCheckBox::indicator {
Expand Down
17 changes: 17 additions & 0 deletions trace/widgets/control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,23 @@ def show_invalid_icon(self, show=True):
def set_active(self, state: int | Qt.CheckState):
checked = Qt.CheckState(state) == Qt.Checked
self.source.setVisible(checked)
self._update_legend(checked)

def _update_legend(self, visible: bool) -> None:
"""Update the legend entry for this curve to match its visibility.
Uses pyqtgraph's native removeItem/addItem since QGraphicsGridLayout
does not collapse hidden items."""
legend = self.plot._legend
if legend is None:
return
if not visible:
legend.removeItem(self.source)
else:
# Only re-add if not already in the legend
for sample, label in legend.items:
if sample.item is self.source:
return
legend.addItem(self.source, self.source.name())

def update_live_icon(self, connected: bool) -> None:
self.live_connection_status.setVisible(not connected)
Expand Down
Loading