@@ -106,6 +106,8 @@ def __init__(
106106 self .stack_acq_vals ["start_position" ].trace_add ("write" , self .update_z_steps )
107107 self .stack_acq_vals ["end_position" ].trace_add ("write" , self .update_z_steps )
108108 self .stack_acq_vals ["start_focus" ].trace_add ("write" , self .update_z_steps )
109+ self .stack_acq_vals ["z_device" ].trace_add ("write" , self .update_additional_stacking_axes )
110+ self .stack_acq_vals ["f_device" ].trace_add ("write" , self .update_additional_stacking_axes )
109111 self .stack_acq_buttons ["set_start" ].configure (
110112 command = self .update_start_position
111113 )
@@ -187,13 +189,26 @@ def initialize(self) -> None:
187189 self .stack_acq_widgets ["cycling" ].widget ["values" ] = ["Per Z" , "Per Stack" ]
188190
189191 # Set the default stage for acquiring a z-stack.
190- self .stack_acq_widgets ["z_device" ].widget ["values" ] = config .z_stages
191- if len (config .z_stages ) == 1 :
192+ z_stages = config .get_stages_by_axis ("z" )
193+ self .stack_acq_widgets ["z_device" ].widget ["values" ] = z_stages
194+ if len (z_stages ) >= 1 :
192195 self .stack_acq_widgets ["z_device" ].widget .current (0 )
193- self .stack_acq_widgets ["z_device" ].widget ["state" ] = "disabled"
194- else :
195- # Now need to allow the user to have an offset between the two stages.
196- self .stack_acq_widgets ["z_offset" ].widget ["state" ] = "normal"
196+
197+ f_stages = config .get_stages_by_axis ("f" )
198+ self .stack_acq_widgets ["f_device" ].widget ["values" ] = f_stages
199+ if len (f_stages ) >= 1 :
200+ self .stack_acq_widgets ["f_device" ].widget .current (0 )
201+
202+ axes = config .stage_axes
203+ axes = [axis for axis in axes if axis not in ("x" , "y" , "theta" )]
204+ devices_dict = {}
205+ for axis in axes :
206+ temp = config .get_stages_by_axis (axis )
207+ for device in temp :
208+ device_name , axis = device .split (" - " )
209+ devices_dict [axis ] = device_name
210+ self .view .stack_acq_frame .create_additional_stack_widgets (axes , devices_dict )
211+
197212
198213 self .filter_wheel_delay = [
199214 config .filter_wheel_setting_dict [i ]["filter_wheel_delay" ]
@@ -225,6 +240,27 @@ def populate_experiment_values(self) -> None:
225240 self .set_info (self .stack_acq_vals , self .microscope_state_dict )
226241 self .set_info (self .timepoint_vals , self .microscope_state_dict )
227242
243+ # set advanced stack acquistion settings
244+ for axis in ["z" , "f" ]:
245+ devices = self .stack_acq_widgets [f"{ axis } _device" ].widget ["values" ]
246+ idx = 0
247+ for i , device in enumerate (devices ):
248+ if device .endswith (self .microscope_state_dict .get (f"primary_{ axis } _axis" , axis )):
249+ idx = i
250+ break
251+ self .stack_acq_widgets [f"{ axis } _device" ].widget .current (idx )
252+
253+ secondary_stack_settings = self .microscope_state_dict .get ("secondary_stack_settings" , {})
254+ variable_dict = self .view .stack_acq_frame .additional_stack_setting_variables
255+ for axis in secondary_stack_settings .keys ():
256+ index_axis = f"stack_{ axis } "
257+ if index_axis in variable_dict :
258+ variable_dict [index_axis ].set (True )
259+ self .view .stack_acq_frame .update_setting_widgets (axis )()
260+ variable_dict [f"{ axis } _offset" ].set (secondary_stack_settings [axis ])
261+
262+ self .update_additional_stacking_axes ()
263+
228264 # check configuration for multi-position settings
229265 self .is_multiposition_val .set (self .microscope_state_dict ["is_multiposition" ])
230266 self .is_multiposition_cache = self .is_multiposition
@@ -339,7 +375,8 @@ def set_mode(self, mode: str) -> None:
339375 acquisition mode
340376 """
341377
342- # TODO: Why do we have mode and image_mode?
378+ # image_mode: imaging mode, e.g., "live", "single", "z-stack", "customized"
379+ # stack acquisition settings are disabled in "live" and "single" mode.
343380 image_mode = self .microscope_state_dict ["image_mode" ]
344381 self .mode = mode
345382 self .channel_setting_controller .set_mode (mode )
@@ -359,9 +396,18 @@ def set_mode(self, mode: str) -> None:
359396 "step_size" ,
360397 ]:
361398 self .stack_acq_widgets [widget_name ].widget ["state" ] = state
362- self .stack_acq_widgets ["cycling" ].widget ["state" ] = (
363- "readonly" if state == "normal" else "disabled"
364- )
399+ for widget_name in ["cycling" , "z_device" , "f_device" ]:
400+ self .stack_acq_widgets [widget_name ].widget ["state" ] = (
401+ "readonly" if state == "normal" else "disabled"
402+ )
403+ for widget_name in self .view .stack_acq_frame .additional_stack_setting_variables :
404+ if widget_name .startswith ("stack_" ):
405+ self .stack_acq_widgets [widget_name ]["state" ] = state
406+ elif widget_name .endswith ("_offset" ):
407+ self .stack_acq_widgets [widget_name ]["state" ] = state
408+ if state == "normal" :
409+ self .update_additional_stacking_axes ()
410+
365411 self .view .stack_timepoint_frame .save_check ["state" ] = (
366412 "normal" if image_mode == "single" and mode == "stop" else state
367413 )
@@ -408,13 +454,17 @@ def update_z_steps(self, *_: tuple[str]) -> None:
408454 step_size = float (self .stack_acq_vals ["step_size" ].get ())
409455 if step_size < 0.001 :
410456 self .stack_acq_vals ["number_z_steps" ].set (0 )
411- self .stack_acq_vals ["abs_z_start" ].set (0 )
412- self .stack_acq_vals ["abs_z_end" ].set (0 )
457+ self .microscope_state_dict ["abs_z_start" ] = 0
458+ self .microscope_state_dict ["abs_z_end" ] = 0
459+ # self.stack_acq_vals["abs_z_start"].set(0)
460+ # self.stack_acq_vals["abs_z_end"].set(0)
413461 return
414462 except tk .TclError :
415463 self .stack_acq_vals ["number_z_steps" ].set (0 )
416- self .stack_acq_vals ["abs_z_start" ].set (0 )
417- self .stack_acq_vals ["abs_z_end" ].set (0 )
464+ self .microscope_state_dict ["abs_z_start" ] = 0
465+ self .microscope_state_dict ["abs_z_end" ] = 0
466+ # self.stack_acq_vals["abs_z_start"].set(0)
467+ # self.stack_acq_vals["abs_z_end"].set(0)
418468 return
419469 except (KeyError , AttributeError ):
420470 logger .error ("Error caught: updating z_steps" )
@@ -428,11 +478,15 @@ def update_z_steps(self, *_: tuple[str]) -> None:
428478 # Shift the start/stop positions by the relative position
429479 flip_flags = self .parent_controller .configuration_controller .stage_flip_flags
430480 if flip_flags ["z" ]:
431- self .stack_acq_vals ["abs_z_start" ].set (self .z_origin + end_position )
432- self .stack_acq_vals ["abs_z_end" ].set (self .z_origin + start_position )
481+ self .microscope_state_dict ["abs_z_start" ] = self .z_origin + end_position
482+ self .microscope_state_dict ["abs_z_end" ] = self .z_origin + start_position
483+ # self.stack_acq_vals["abs_z_start"].set(self.z_origin + end_position)
484+ # self.stack_acq_vals["abs_z_end"].set(self.z_origin + start_position)
433485 else :
434- self .stack_acq_vals ["abs_z_start" ].set (self .z_origin + start_position )
435- self .stack_acq_vals ["abs_z_end" ].set (self .z_origin + end_position )
486+ self .microscope_state_dict ["abs_z_start" ] = self .z_origin + start_position
487+ self .microscope_state_dict ["abs_z_end" ] = self .z_origin + end_position
488+ # self.stack_acq_vals["abs_z_start"].set(self.z_origin + start_position)
489+ # self.stack_acq_vals["abs_z_end"].set(self.z_origin + end_position)
436490
437491 # update experiment MicroscopeState dict
438492 self .microscope_state_dict ["start_position" ] = start_position
@@ -441,10 +495,13 @@ def update_z_steps(self, *_: tuple[str]) -> None:
441495 - 1 if flip_flags ["z" ] else 1
442496 )
443497 self .microscope_state_dict ["number_z_steps" ] = number_z_steps
444- self .microscope_state_dict ["abs_z_start" ] = self .stack_acq_vals [
445- "abs_z_start"
446- ].get ()
447- self .microscope_state_dict ["abs_z_end" ] = self .stack_acq_vals ["abs_z_end" ].get ()
498+ self .stack_acq_vals ["bottom" ].set (
499+ self .microscope_state_dict ["abs_z_start" ]
500+ )
501+ self .stack_acq_vals ["top" ].set (
502+ self .microscope_state_dict ["abs_z_end" ]
503+ )
504+
448505 try :
449506 self .microscope_state_dict ["start_focus" ] = self .stack_acq_vals [
450507 "start_focus"
@@ -814,6 +871,25 @@ def update_experiment_values(self) -> None:
814871 self .channel_setting_controller .update_experiment_values ()
815872 self .update_z_steps ()
816873
874+ # update primary/secondary stack acquisition stage settings
875+ primary_z_stage = self .stack_acq_vals ["z_device" ].get ()
876+ primary_z_axis = primary_z_stage .split (" - " )[1 ]
877+ primary_f_stage = self .stack_acq_vals ["f_device" ].get ()
878+ primary_f_axis = primary_f_stage .split (" - " )[1 ]
879+
880+ self .microscope_state_dict ["primary_z_axis" ] = primary_z_axis
881+ self .microscope_state_dict ["primary_f_axis" ] = primary_f_axis
882+
883+ secondary_stack_settings = {}
884+ variable_dict = self .view .stack_acq_frame .additional_stack_setting_variables
885+ for k in variable_dict .keys ():
886+ if k .startswith ("stack_" ) and variable_dict [k ].get ():
887+ axis = k .split ("_" )[1 ]
888+ offset = variable_dict [f"{ axis } _offset" ].get ()
889+ secondary_stack_settings [axis ] = offset
890+
891+ self .microscope_state_dict ["secondary_stack_settings" ] = secondary_stack_settings
892+
817893 def verify_experiment_values (self ) -> str :
818894 """Verify channel tab settings and return warning info
819895
@@ -858,6 +934,34 @@ def set_exposure_time(self, channel_exposure_time: tuple[str, float]) -> None:
858934 self .channel_setting_controller .view .exptime_variables [idx ].set (exposure_time )
859935 self .channel_setting_controller .in_initialization = False
860936
937+ def update_additional_stacking_axes (self , * args , ** kwargs ):
938+ if self .stack_acq_vals ["z_device" ].get ():
939+ z_axis = self .stack_acq_vals ["z_device" ].get ().split (" - " )[1 ]
940+ else :
941+ z_axis = ""
942+ if self .stack_acq_vals ["f_device" ].get ():
943+ f_axis = self .stack_acq_vals ["f_device" ].get ().split (" - " )[1 ]
944+ else :
945+ f_axis = ""
946+
947+ # enable all axis
948+ for widget_name in self .view .stack_acq_frame .additional_stack_setting_variables :
949+ if widget_name .startswith ("stack_" ):
950+ self .stack_acq_widgets [widget_name ].state (["!disabled" ])
951+
952+ # disable primary z and f
953+ variable_dict = self .view .stack_acq_frame .additional_stack_setting_variables
954+ if f"stack_{ z_axis } " in variable_dict :
955+ self .stack_acq_widgets [f"stack_{ z_axis } " ].state (["disabled" ])
956+ if variable_dict [f"stack_{ z_axis } " ].get ():
957+ variable_dict [f"stack_{ z_axis } " ].set (False )
958+ self .view .stack_acq_frame .update_setting_widgets (z_axis )()
959+ if f"stack_{ f_axis } " in variable_dict :
960+ self .stack_acq_widgets [f"stack_{ f_axis } " ].state (["disabled" ])
961+ if variable_dict [f"stack_{ f_axis } " ].get ():
962+ variable_dict [f"stack_{ f_axis } " ].set (False )
963+ self .view .stack_acq_frame .update_setting_widgets (f_axis )()
964+
861965 @property
862966 def custom_events (self ) -> dict [str , callable ]:
863967 """Custom events for the channels tab."""
0 commit comments