1616from PySide6 .QtWidgets import (
1717 QVBoxLayout , QLabel , QWidget , QSplitter , QPushButton , QScrollArea , QHBoxLayout , QMenu , QTabWidget , QCheckBox , QMessageBox
1818)
19- from PySide6 .QtCore import Qt , QPointF , QRectF
20- from PySide6 .QtGui import QContextMenuEvent , QKeyEvent , QResizeEvent , QIcon
19+ from PySide6 .QtCore import Qt , QPointF , QRectF , QRect
20+ from PySide6 .QtGui import QContextMenuEvent , QKeyEvent , QResizeEvent , QIcon , QPainter , QPen
2121
2222from scrutiny import sdk
2323from scrutiny .sdk import EmbeddedDataType
2828from scrutiny .sdk .client import ScrutinyClient
2929
3030from scrutiny .gui import assets
31- from scrutiny .gui .themes import scrutiny_get_theme
31+ from scrutiny .gui .themes import scrutiny_get_theme , scrutiny_get_theme_prop , ScrutinyThemeProperties
3232from scrutiny .gui .tools import prompt
3333from scrutiny .gui .widgets .watchable_line_edit import WatchableLineEdit
3434from scrutiny .gui .components .locals .base_local_component import ScrutinyGUIBaseLocalComponent
@@ -54,6 +54,7 @@ class DisplaySource(enum.Enum):
5454
5555
5656class State :
57+ """The state that can be saved and reloaded when saving the dashboard"""
5758
5859 class Watchable (TypedDict ):
5960 fqn : str
@@ -93,7 +94,7 @@ class EmbeddedGraphState:
9394 waiting_on_graph : bool
9495 """Waiting on an acquisition to complete"""
9596 chart_toolbar_wanted : bool
96- """The suer wants to see the chart toolbar"""
97+ """The user wants to see the chart toolbar"""
9798 has_failure_message : bool
9899 """There's a failure message being displayed on the chartview"""
99100
@@ -142,6 +143,9 @@ def enable_reset_zoom_button(self) -> bool:
142143 def must_display_toolbar (self ) -> bool :
143144 return self .can_display_toolbar () and self .chart_toolbar_wanted and self .has_content
144145
146+ def must_display_show_trigger_checkbox (self ) -> bool :
147+ return self .has_content
148+
145149 def hide_chart_toolbar (self ) -> None :
146150 self .chart_toolbar_wanted = False
147151
@@ -166,6 +170,47 @@ class InitialGraphListDownloadConditions:
166170 firmware_id : Optional [str ]
167171
168172
173+ class EmbeddedGraphChartView (ScrutinyChartView ):
174+
175+ _trigger_xval :float
176+ _show_trigger :bool
177+ _trigger_pen :QPen
178+
179+ @tools .copy_type (ScrutinyChartView .__init__ )
180+ def __init__ (self , * args :Any , ** kwargs :Any ) -> None :
181+ super ().__init__ (* args , ** kwargs )
182+ self ._trigger_xval = 0
183+ self ._show_trigger = False
184+ self ._trigger_pen = QPen ()
185+ self ._trigger_pen .setStyle (Qt .PenStyle .DashLine )
186+ self ._trigger_pen .setColor (scrutiny_get_theme_prop (ScrutinyThemeProperties .EMBEDDED_GRAPH_CHART_TRIGGER_COLOR ))
187+
188+ def show_trigger_marker_at (self , xval :float ) -> None :
189+ self ._trigger_xval = xval
190+ self .show_trigger_marker ()
191+
192+ def show_trigger_marker (self ) -> None :
193+ self ._show_trigger = True
194+ self ._invalidate_forground ()
195+
196+ def remove_trigger_marker (self ) -> None :
197+ self ._show_trigger = False
198+ self ._invalidate_forground ()
199+
200+ def drawForeground (self , painter : QPainter , rect : Union [QRectF , QRect ]) -> None :
201+ super ().drawForeground (painter , rect )
202+ xaxis = self .chart ().axisX ()
203+ if self ._show_trigger and xaxis is not None :
204+ chart = self .chart ()
205+ plotarea_mapped_to_chartview = chart .mapRectToParent (chart .plotArea ())
206+ trigger_xpos_mapped_to_chart = chart .xval_to_xpos (self ._trigger_xval )
207+ if trigger_xpos_mapped_to_chart :
208+ trigger_xpos = chart .mapToParent (trigger_xpos_mapped_to_chart , 0 ).x () # Map it to this chartview
209+ y1 = plotarea_mapped_to_chartview .y ()
210+ y2 = plotarea_mapped_to_chartview .y () + plotarea_mapped_to_chartview .height ()
211+ painter .setPen (self ._trigger_pen )
212+ painter .drawLine (QPointF (trigger_xpos , y1 ), QPointF (trigger_xpos , y2 ))
213+
169214class EmbeddedGraphComponent (ScrutinyGUIBaseLocalComponent ):
170215 instance_name : str
171216
@@ -186,9 +231,11 @@ class EmbeddedGraphComponent(ScrutinyGUIBaseLocalComponent):
186231 """3 section splitter separating left / center / right"""
187232 _xval_label : QLabel
188233 """The label used to display the X-Value when moving the graph cursor (red vertical line)"""
234+ _chk_show_trigger :QCheckBox
235+ """A checkbox to show or hide the trigger marker"""
189236 _signal_tree : GraphSignalTree
190237 """The right side signal tree. contains the watchable we want to log / those present in the displayed graph"""
191- _chartview : ScrutinyChartView
238+ _chartview : EmbeddedGraphChartView
192239 """The QT element showing the chart"""
193240 _chart_toolbar : ScrutinyChartToolBar
194241 """Custom toolbar at the top of the graph selecting the zoom mode and cursor mode"""
@@ -221,7 +268,7 @@ class EmbeddedGraphComponent(ScrutinyGUIBaseLocalComponent):
221268 _graph_browse_list_widget : GraphBrowseListWidget
222269 """The list displaying the available acquisitions on the server"""
223270 _chk_browse_loaded_sfd_only : QCheckBox
224- """A checkbox that filters the content of the acquisition list by keeping only those taken by the firmware presnetly loaded"""
271+ """A checkbox that filters the content of the acquisition list by keeping only those taken by the firmware presently loaded"""
225272 _browse_feedback_label : FeedbackLabel
226273 """A label to display messages visible only in the "Browse" tab"""
227274 _btn_delete_all : QPushButton
@@ -268,6 +315,8 @@ def make_right_pane() -> QWidget:
268315 right_pane_layout .setContentsMargins (0 , 0 , 0 , 0 )
269316
270317 self ._xval_label = QLabel ()
318+ self ._chk_show_trigger = QCheckBox ("Show Trigger" )
319+ self ._chk_show_trigger .checkStateChanged .connect (self ._chk_show_trigger_changed_slot )
271320
272321 # Series on continuous graph don't have their X value aligned.
273322 # We can only show the value next to each point, not all together in the tree
@@ -277,6 +326,7 @@ def make_right_pane() -> QWidget:
277326
278327 self ._xval_label .setVisible (False )
279328 right_pane_layout .addWidget (self ._xval_label )
329+ right_pane_layout .addWidget (self ._chk_show_trigger )
280330 right_pane_layout .addWidget (self ._signal_tree )
281331
282332 right_pane_scroll = QScrollArea (self )
@@ -291,7 +341,7 @@ def make_right_pane() -> QWidget:
291341 def make_center_pane () -> QWidget :
292342 chart = ScrutinyChart ()
293343
294- self ._chartview = ScrutinyChartView (self )
344+ self ._chartview = EmbeddedGraphChartView (self )
295345 self ._chartview .setChart (chart )
296346 self ._xaxis = None
297347 self ._yaxes = []
@@ -599,6 +649,11 @@ def _apply_internal_state(self) -> None:
599649 self ._btn_load_more .setText ("Load" )
600650 else :
601651 self ._btn_load_more .setText ("Load more" )
652+
653+ if self ._state .must_display_show_trigger_checkbox ():
654+ self ._chk_show_trigger .show ()
655+ else :
656+ self ._chk_show_trigger .hide ()
602657
603658 self ._btn_load_more .setEnabled (self ._state .enable_load_more_button ())
604659 self ._btn_delete_all .setEnabled (self ._state .enable_delete_all_button ())
@@ -792,6 +847,16 @@ def _display_acquisition(self, acquisition: DataloggingAcquisition, source: Disp
792847 self ._state .allow_chart_toolbar ()
793848 self ._chart_toolbar .disable_chart_cursor ()
794849
850+ # Configure the trigger marker. It is possible that there is no trigger index
851+ if acquisition .trigger_index is not None :
852+ self ._chartview .show_trigger_marker_at (xseries_data [acquisition .trigger_index ])
853+ self ._chk_show_trigger .setChecked (True )
854+ self ._chk_show_trigger .setEnabled (True )
855+ else :
856+ self ._chartview .remove_trigger_marker ()
857+ self ._chk_show_trigger .setChecked (False )
858+ self ._chk_show_trigger .setEnabled (False )
859+
795860 # Enable the chart cursor so it can display values in the signal tree
796861 def update_xval (val : float , enabled : bool ) -> None :
797862 self ._xval_label .setText (f"{ acquisition .xdata .name } : { val } " )
@@ -949,6 +1014,12 @@ def _signal_tree_content_changed_slot(self) -> None:
9491014 """A watchable has been added/remove from the watchable tree"""
9501015 self ._graph_config_widget .update_content ()
9511016
1017+ def _chk_show_trigger_changed_slot (self , state :Qt .CheckState ) -> None :
1018+ if state == Qt .CheckState .Checked :
1019+ self ._chartview .show_trigger_marker ()
1020+ else :
1021+ self ._chartview .remove_trigger_marker ()
1022+
9521023 def update_emphasize_state (self ) -> None :
9531024 """Read the items in the SignalTree object (right menu with axis) and update the size/boldness of the graph series
9541025 based on wether they are selected or not"""
0 commit comments