From fc2a87ef85b228217898ac08f30152272cb3a4fa Mon Sep 17 00:00:00 2001 From: Markus Rosenstihl Date: Wed, 18 Mar 2026 15:11:46 +0100 Subject: [PATCH 1/3] moved cursor toggle to context menu --- src/gui/DamarisGUI.py | 69 +++++++++++++------------------------------ 1 file changed, 20 insertions(+), 49 deletions(-) diff --git a/src/gui/DamarisGUI.py b/src/gui/DamarisGUI.py index b943e9c..4d104c1 100644 --- a/src/gui/DamarisGUI.py +++ b/src/gui/DamarisGUI.py @@ -275,14 +275,6 @@ class DamarisGUI: self.toolbar_run_button = self.xml_gui.get_object( "toolbar_run_button" ) self.toolbar_pause_button = self.xml_gui.get_object( "toolbar_pause_button" ) - # print button - #self.toolbar_print_button = self.xml_gui.get_object( "toolbar_print_button" ) - #if not hasattr( gtk, "PrintOperation" ): - # self.toolbar_print_button.set_sensitive( False ) - # print("Printing is not supported by GTK+ version in use") - #else: - # self.toolbar_print_button.set_sensitive( True ) - # prepare for edit state self.toolbar_run_button.set_sensitive( True ) self.toolbar_stop_button.set_sensitive( False ) @@ -2330,16 +2322,6 @@ class MonitorWidgets: except: pass - # Add cursor toggle button to toolbar - self.matplot_cursor = None - separator = gtk.SeparatorToolItem() - self.matplot_toolbar.insert(separator, self.matplot_toolbar.get_n_items()) - cursor_btn = gtk.ToggleToolButton() - cursor_btn.set_label("Cursor") - cursor_btn.set_tooltip_text("Toggle crosshair cursor") - cursor_btn.connect("toggled", self.toggle_cursor) - self.matplot_toolbar.insert(cursor_btn, self.matplot_toolbar.get_n_items()) - self.display_table.attach( self.matplot_toolbar, 0, 1, 1, 2, gtk.AttachOptions.FILL | gtk.AttachOptions.EXPAND, 0, 0, 0 ) self.matplot_toolbar.show( ) @@ -2643,6 +2625,7 @@ class MonitorWidgets: def display_source_changed_event( self, widget, data=None ): new_data_name = self.source_list_current( ) + if (self.displayed_data[ 0 ] is None and new_data_name == "None"): return if (self.displayed_data[ 0 ] == new_data_name): @@ -2765,10 +2748,14 @@ class MonitorWidgets: """Toggle matplotlib crosshair cursor""" from matplotlib.widgets import Cursor if widget.get_active(): + if hasattr(self, 'matplot_cursor') and self.matplot_cursor is not None: + self.matplot_cursor.disconnect_events() self.matplot_cursor = Cursor(self.matplot_axes, useblit=False, color='red', linewidth=1) else: + if hasattr(self, 'matplot_cursor') and self.matplot_cursor is not None: + self.matplot_cursor.disconnect_events() self.matplot_cursor = None - self.matplot_canvas.draw() + self.matplot_canvas.draw_idle() def on_canvas_button_press(self, widget, event): """Handle button press events on matplotlib canvas""" @@ -2781,6 +2768,17 @@ class MonitorWidgets: """Show context menu for matplotlib canvas""" menu = gtk.Menu() + # toggle cursor + toggle_cursor = gtk.CheckMenuItem(label="Crosshair") + # Set the current state based on whether cursor exists + if hasattr(self, 'matplot_cursor') and self.matplot_cursor is not None: + toggle_cursor.set_active(True) + else: + toggle_cursor.set_active(False) + toggle_cursor.connect("toggled", self.toggle_cursor) + menu.append(toggle_cursor) + + # Copy as PNG item_copy_png = gtk.MenuItem(label="Copy as PNG") item_copy_png.connect("activate", self.copy_canvas_as_png) @@ -2862,37 +2860,8 @@ class MonitorWidgets: except Exception as e: log("Error copying figure to clipboard: %s" % str(e)) - # Fall through to text data copy - - # Fallback: copy data as text (original functionality) - # can be removed after thorough testing - data_to_save = self.displayed_data[ : ] - if self.displayed_data[ 1 ] is None: - # nothing to save - return - if not hasattr( data_to_save[ 1 ], "write_to_csv" ): - log( "do not know how to save %s of class/type %s" % (data_to_save[ 0 ], type( data_to_save[ 1 ] )) ) - return - - # tested with qtiplot, labplot, openoffice - # tab delimiters necessary - # comments are not welcome :-( - tmpdata = io.StringIO( ) - data_to_save[ 1 ].write_to_csv( tmpdata, delimiter="\t" ) - # cut away comments - tmpstring = "" - tmpdata.seek( 0 ) - for line in tmpdata: - if line[ 0 ] == "#": - continue - tmpstring += line - del tmpdata - clipboard = gtk.Clipboard.get(gdk.SELECTION_CLIPBOARD) - clipboard.set_text( tmpstring, -1 ) - del tmpstring ##################### functions to feed display - def clear_display( self ): """ unconditionally throw away everything @@ -2918,7 +2887,9 @@ class MonitorWidgets: # clear line plot self.matplot_axes.lines.remove( self.measurementresultline[ 0 ] ) self.measurementresultline = None - + if hasattr(self, 'matplot_cursor') and self.matplot_cursor is not None: + self.matplot_cursor.disconnect_events() + self.matplot_cursor = None if not hasattr( self, "measurementresultgraph" ): self.measurementresultgraph = None elif self.measurementresultgraph is not None: From 9d969da8679e86f0a1869062cbcb6beb9699c560 Mon Sep 17 00:00:00 2001 From: Markus Rosenstihl Date: Wed, 18 Mar 2026 17:21:27 +0100 Subject: [PATCH 2/3] cleanup sources --- src/data/Drawable.py | 10 +--------- src/data/MeasurementResult.py | 3 +-- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/data/Drawable.py b/src/data/Drawable.py index 8ea4bc4..c9f823f 100644 --- a/src/data/Drawable.py +++ b/src/data/Drawable.py @@ -128,12 +128,10 @@ class Drawable: def set_legend(self, channel, value): "Sets the legend of the plot" - if key in self.legend: + if channel in self.legend: print("Drawable Warning: Legend key \"%s\" will be overwritten with \"%s\"" % (str(channel), str(value))) - self.legend[channel] = str(value) - def get_xmin(self): "Returns minimun of x" return self.x.min() @@ -142,17 +140,14 @@ class Drawable: "Sets minimum of x" self.xmin = xmin - def get_xmax(self): "Returns maximum of x" return self.x.max() - def set_xmax(self, xmax): "Sets maximum of x" self.xmax = xmax - def get_ymin(self): "Returns minimum of y" if type(self.y)==type([]): @@ -160,12 +155,10 @@ class Drawable: else: return self.y.min() - def set_ymin(self, ymin): "Sets minimum of y" self.ymin = ymin - def get_ymax(self): "Returns maximimum of y" if type(self.y)==type([]): @@ -173,7 +166,6 @@ class Drawable: else: return self.y.max() - def set_ymax(self, ymax): "Sets maximum of y" self.ymax = ymax diff --git a/src/data/MeasurementResult.py b/src/data/MeasurementResult.py index 53d00c2..a7c0f63 100644 --- a/src/data/MeasurementResult.py +++ b/src/data/MeasurementResult.py @@ -136,7 +136,7 @@ class MeasurementResult(Drawable.Drawable, collections.UserDict): Drawable.Drawable.__init__(self) collections.UserDict.__init__(self) self.quantity_name=quantity_name - self.lock=threading.RLock() + self.lock = threading.RLock() # get the selected item, if it does not exist, create an empty one def __getitem__(self, key): @@ -226,7 +226,6 @@ class MeasurementResult(Drawable.Drawable, collections.UserDict): def write_to_hdf(self, hdffile, where, name, title, complib=None, complevel=None): - h5_table_format= { "x" : tables.Float32Col(), "y" : tables.Float32Col(), From 2a921d97065dc5d8e559442de77c40921b31e38c Mon Sep 17 00:00:00 2001 From: Markus Rosenstihl Date: Wed, 18 Mar 2026 17:21:47 +0100 Subject: [PATCH 3/3] more precise SyntaxError indicator --- src/gui/DamarisGUI.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gui/DamarisGUI.py b/src/gui/DamarisGUI.py index 4d104c1..9b0a934 100644 --- a/src/gui/DamarisGUI.py +++ b/src/gui/DamarisGUI.py @@ -418,9 +418,8 @@ class DamarisGUI: lo = 0 print("Experiment Script: %s at line %d, col %d:" % (e.__class__.__name__, ln, lo)) if e.text != "": - print("\"%s\"" % e.text) - # print " "*(e.offset+1)+"^" # nice idea, but needs monospaced fonts - pass + print(e.text.rstrip()) + print(" "*(e.offset-1)+"^") print(e) res_code = None @@ -1080,6 +1079,8 @@ class LogWindow: self.damaris_gui = damaris_gui self.textview = self.xml_gui.get_object( "messages_textview" ) self.textview.connect( "key-press-event", self.textview_keypress) + font_desc = pango.FontDescription("Monospace 10") + self.textview.modify_font(font_desc) self.textbuffer = self.textview.get_buffer( ) self.logstream = log self.logstream.gui_log = self @@ -1951,9 +1952,12 @@ class ConfigTab: self.config_del_jobs_after_execution_checkbutton = self.xml_gui.get_object( "del_jobs_after_execution_checkbutton" ) self.config_data_pool_name_entry = self.xml_gui.get_object( "data_pool_name_entry" ) + self.config_data_pool_name_entry.set_tooltip_text("Use %(date)s for ISO date or %(datetime)s for ISO date+time") self.config_data_pool_write_interval_entry = self.xml_gui.get_object( "data_pool_write_interval_entry" ) self.config_data_pool_complib = self.xml_gui.get_object( "CompLibs" ) + self.config_data_pool_complib.set_tooltip_text("Use zlib for best compatibility with other tools") self.config_data_pool_comprate = self.xml_gui.get_object( "CompRatio" ) + self.config_data_pool_comprate.set_tooltip_text("Use 1 for best compression, 9 for best speed; 3 is very usable") self.config_info_textview = self.xml_gui.get_object( "info_textview" ) self.config_script_font_button = self.xml_gui.get_object( "script_fontbutton" )