@@ -178,22 +178,23 @@ def on_selection_list_selection_toggled(
178178
179179
180180# --------------------------------------------------------------------------------------
181- # DatatypeCheckboxes
181+ # BaseDatatypeCheckboxes
182182# --------------------------------------------------------------------------------------
183183
184184
185- class DatatypeCheckboxes (Static ):
185+ class BaseDatatypeCheckboxes (Static ):
186186 """Dynamically-populated checkbox widget for convenient datatype selection.
187187
188- Parameters
189- ----------
190- settings_key
191- 'create' if datatype checkboxes for the create tab,
192- 'transfer' for the transfer tab. Transfer tab includes
193- additional datatype options (e.g. "all").
188+ Base class for a widget that allows the user to select datatypes.
189+ The checkbox names are generated in the persistent_settings
190+ configuration file, which stores all checkbox visible and
191+ checked status across datashuttle sessions.
194192
195193 Attributes
196194 ----------
195+ tab_name
196+ Set by the subclass, indicates if the settings and checkbox names
197+ should include "create" or "transfer"
197198 datatype_config
198199 A Dictionary containing datatype as key (e.g. "ephys", "behav")
199200 and values are `bool` indicating whether the checkbox is on / off.
@@ -210,32 +211,29 @@ class DatatypeCheckboxes(Static):
210211
211212 """
212213
214+ tab_name : Literal ["create" , "transfer" ] # must be set by subclass
215+
213216 def __init__ (
214217 self ,
215218 interface : Interface ,
216- create_or_transfer : Literal ["create" , "transfer" ] = "create" ,
217219 id : Optional [str ] = None ,
218220 ) -> None :
219- """Initialise the DatatypeCheckboxes .
221+ """Initialise the BaseDatatypeCheckboxes .
220222
221223 Parameters
222224 ----------
223225 interface
224226 Datashuttle Interface object.
225227
226- create_or_transfer
227- Whether we are on the "create" or "transfer" tab.
228-
229228 id
230- Textual ID for the DatatypeCheckboxes widget.
229+ Textual ID for the BaseDatatypeCheckboxes widget.
231230
232231 """
233- super (DatatypeCheckboxes , self ).__init__ (id = id )
232+ super (BaseDatatypeCheckboxes , self ).__init__ (id = id )
234233
235234 self .interface = interface
236- self .create_or_transfer = create_or_transfer
237235
238- self .settings_key = get_tui_settings_key_name (self .create_or_transfer )
236+ self .settings_key = get_tui_settings_key_name (self .tab_name )
239237
240238 # `datatype_config` is basically just a convenience wrapper
241239 # around interface.get_tui_settings
@@ -244,17 +242,17 @@ def __init__(
244242 ]
245243
246244 def compose (self ) -> ComposeResult :
247- """Add widgets to the DatatypeCheckboxes ."""
245+ """Add widgets to the BaseDatatypeCheckboxes ."""
248246 for datatype , setting in self .datatype_config .items ():
249247 if setting ["displayed" ]:
250248 yield Checkbox (
251249 datatype .replace ("_" , " " ),
252- id = get_checkbox_name (self .create_or_transfer , datatype ),
250+ id = get_checkbox_name (self .tab_name , datatype ),
253251 value = setting ["on" ],
254252 )
255253
256254 @on (Checkbox .Changed )
257- def on_checkbox_changed (self ) -> None :
255+ def on_checkbox_changed (self , event : Checkbox . Changed ) -> None :
258256 """Handle a datatype checkbox change.
259257
260258 When a checkbox is changed, update the `self.datatype_config`
@@ -264,19 +262,19 @@ def on_checkbox_changed(self) -> None:
264262 for datatype in self .datatype_config .keys ():
265263 if self .datatype_config [datatype ]["displayed" ]:
266264 self .datatype_config [datatype ]["on" ] = self .query_one (
267- f"#{ get_checkbox_name (self .create_or_transfer , datatype )} "
265+ f"#{ get_checkbox_name (self .tab_name , datatype )} "
268266 ).value
269267
270268 self .interface .save_tui_settings (
271269 self .datatype_config , self .settings_key
272270 )
273271
274272 def on_mount (self ) -> None :
275- """Add widgets to the DatatypeCheckboxes ."""
273+ """Add widgets to the BaseDatatypeCheckboxes ."""
276274 for datatype in self .datatype_config .keys ():
277275 if self .datatype_config [datatype ]["displayed" ]:
278276 self .query_one (
279- f"#{ get_checkbox_name (self .create_or_transfer , datatype )} "
277+ f"#{ get_checkbox_name (self .tab_name , datatype )} "
280278 ).tooltip = tooltips [datatype ]
281279
282280 def selected_datatypes (self ) -> List [str ]:
@@ -289,22 +287,103 @@ def selected_datatypes(self) -> List[str]:
289287 return selected_datatypes
290288
291289
290+ class CreateDatatypeCheckboxes (BaseDatatypeCheckboxes ):
291+ """Subclass of the data-type checkboxes for the "create" tab."""
292+
293+ tab_name : Literal ["create" , "transfer" ] = "create"
294+
295+
296+ class TransferDatatypeCheckboxes (BaseDatatypeCheckboxes ):
297+ """Subclass of the data type checkboxes class for the transfer tab.
298+
299+ This subclass extends `on_checkbox_changed` by adding logic to
300+ dynamically turn off mutually exclusive checkboxes when one is
301+ selected, before delegating to the base implementation.
302+
303+ """
304+
305+ tab_name : Literal ["create" , "transfer" ] = "transfer"
306+
307+ def __init__ (self , interface : Interface , id : Optional [str ]):
308+ """Initialise TransferDatatypeCheckboxes.
309+
310+ Parameters
311+ ----------
312+ interface
313+ Datashuttle Interface object.
314+
315+ id
316+ Textual ID for the DatatypeCheckboxes widget.
317+
318+ """
319+ super ().__init__ (interface , id )
320+
321+ @on (Checkbox .Changed )
322+ def on_checkbox_changed (self , event : Checkbox .Changed ) -> None :
323+ """Dynamically turn off checkboxes depending on the activated checkbox then save.
324+
325+ In the transfer tab, we have a few different checkboxes that
326+ are mutually exclusive. For example, `all` and `all_datatype`
327+ are redundant. This function turns off checkboxes redundant
328+ with the selected checkbox, before calling the super class
329+ which saves the state of the currently selected checkboxes.
330+ """
331+ checkbox = event .control
332+ checkbox_name = get_datatype_from_checkbox_name (str (checkbox .id ))
333+
334+ if checkbox .value :
335+ all_datatypes_list = [
336+ dtype
337+ for dtype in self .datatype_config .keys ()
338+ if dtype not in ["all" , "all_datatype" , "all_non_datatype" ]
339+ ]
340+
341+ if checkbox_name == "all" :
342+ to_turn_off = [
343+ "all_datatype" ,
344+ "all_non_datatype" ,
345+ ] + all_datatypes_list
346+
347+ elif checkbox_name == "all_datatype" :
348+ to_turn_off = ["all" ] + all_datatypes_list
349+
350+ elif checkbox_name == "all_non_datatype" :
351+ to_turn_off = ["all" ]
352+
353+ else :
354+ to_turn_off = ["all" , "all_datatype" ]
355+
356+ for datatype in to_turn_off :
357+ if self .datatype_config [datatype ]["displayed" ]:
358+ self .query_one (
359+ f"#{ get_checkbox_name (self .tab_name , datatype )} "
360+ ).value = False
361+
362+ super ().on_checkbox_changed (event )
363+
364+
292365# Helpers
293366# --------------------------------------------------------------------------------------
294367
295368
296369def get_checkbox_name (
297- create_or_transfer : Literal ["create" , "transfer" ], datatype
370+ tab_name : Literal ["create" , "transfer" ], datatype
298371) -> str :
299372 """Return a canonical formatted checkbox name."""
300- return f"{ create_or_transfer } _{ datatype } _checkbox"
373+ return f"{ tab_name } _{ datatype } _checkbox"
374+
375+
376+ def get_datatype_from_checkbox_name (checkbox_name : str ) -> str :
377+ """Get the datatype from the output of `get_checkbox_name()`."""
378+ split_datatype = checkbox_name .split ("_" )[1 :- 1 ]
379+ return "_" .join (split_datatype )
301380
302381
303382def get_tui_settings_key_name (
304- create_or_transfer : Literal ["create" , "transfer" ],
383+ tab_name : Literal ["create" , "transfer" ],
305384) -> str :
306385 """Return the canonical tui settings key."""
307- if create_or_transfer == "create" :
386+ if tab_name == "create" :
308387 settings_key = "create_checkboxes_on"
309388 else :
310389 settings_key = "transfer_checkboxes_on"
0 commit comments