3333from .window_utils import requested_switch_state , set_switch_confirmed_state
3434
3535APO_IMPORT_LABEL_PREFIX = "Imported APO: "
36+ DELETED_PRESET_LABEL_PREFIX = "Unsaved copy: "
3637
3738
3839def imported_apo_curve_label (path : str ) -> str :
@@ -201,10 +202,54 @@ def suggested_save_as_name(self) -> str:
201202 label = self .current_curve_source_label ()
202203 if label and label .startswith (APO_IMPORT_LABEL_PREFIX ):
203204 return sanitize_preset_name (label [len (APO_IMPORT_LABEL_PREFIX ) :])
205+ if label and label .startswith (DELETED_PRESET_LABEL_PREFIX ):
206+ return sanitize_preset_name (label [len (DELETED_PRESET_LABEL_PREFIX ) :])
204207 if label == "Imported APO" :
205208 return label
206209 return ""
207210
211+ def preset_name_exists (self , name : str ) -> bool :
212+ return preset_path_for_name (name ).exists ()
213+
214+ def confirm_preset_replacement (
215+ self ,
216+ preset_name : str ,
217+ body : str ,
218+ replace_callback : Callable [[], None ],
219+ ) -> None :
220+ dialog = Adw .AlertDialog ()
221+ dialog .set_heading ("Replace preset?" )
222+ dialog .set_body (body )
223+ dialog .add_response ("cancel" , "Cancel" )
224+ dialog .add_response ("replace" , "Replace" )
225+ dialog .set_default_response ("cancel" )
226+ dialog .set_close_response ("cancel" )
227+ dialog .set_response_appearance ("replace" , Adw .ResponseAppearance .DESTRUCTIVE )
228+ dialog .choose (
229+ self ,
230+ None ,
231+ lambda dialog , result : self .on_preset_replace_dialog_done (dialog , result , replace_callback ),
232+ )
233+
234+ def on_preset_replace_dialog_done (
235+ self ,
236+ dialog : Adw .AlertDialog ,
237+ result : Gio .AsyncResult ,
238+ replace_callback : Callable [[], None ],
239+ ) -> None :
240+ try :
241+ response = dialog .choose_finish (result )
242+ except GLib .Error :
243+ return
244+
245+ if response != "replace" :
246+ return
247+
248+ try :
249+ replace_callback ()
250+ except Exception as exc :
251+ self .set_status (str (exc ))
252+
208253 def output_preset_is_active (self ) -> bool :
209254 linked_preset = self .output_preset_link_name ()
210255 return bool (
@@ -539,6 +584,21 @@ def save_current_state_to_preset(self, name: str) -> None:
539584 self .notify_control_presets_changed ()
540585 self .notify_control_state_changed ()
541586
587+ def save_current_state_to_preset_as (self , name : str ) -> None :
588+ preset_name = sanitize_preset_name (name )
589+ if not preset_name :
590+ raise ValueError ("Preset name is empty" )
591+
592+ if preset_name != self .current_preset_name and self .preset_name_exists (preset_name ):
593+ self .confirm_preset_replacement (
594+ preset_name ,
595+ f"{ preset_name } already exists. Replace it with the current curve?" ,
596+ lambda : self .save_current_state_to_preset (preset_name ),
597+ )
598+ return
599+
600+ self .save_current_state_to_preset (preset_name )
601+
542602 def load_library_preset (
543603 self ,
544604 name : str ,
@@ -756,7 +816,7 @@ def on_preset_save_clicked(self, button: Gtk.Button) -> None:
756816
757817 def on_preset_save_as_clicked (self , button : Gtk .Button ) -> None :
758818 initial_name = self .suggested_save_as_name ()
759- self .prompt_for_preset_name ("Save Preset As" , "Save" , initial_name , self .save_current_state_to_preset )
819+ self .prompt_for_preset_name ("Save Preset As" , "Save" , initial_name , self .save_current_state_to_preset_as )
760820
761821 def on_preset_revert_clicked (self , button : Gtk .Button ) -> None :
762822 if self .current_preset_name is not None :
@@ -907,7 +967,7 @@ def on_preset_delete_dialog_done(
907967 delete_preset_file (preset_name )
908968 self .current_preset_name = None
909969 self .saved_preset_signature = self .controller .state_signature ()
910- self .clear_curve_revert_baseline ( )
970+ self .set_curve_revert_baseline ( f" { DELETED_PRESET_LABEL_PREFIX } { preset_name } " )
911971 self .refresh_preset_list ()
912972 self .sync_ui_from_state ()
913973 self .set_status (f"Deleted Preset: { preset_name } ; Current Curve Kept" )
@@ -927,6 +987,20 @@ def on_preset_import_clicked(self, button: Gtk.Button) -> None:
927987 dialog .set_default_filter (file_filter )
928988 dialog .open (self , None , self .on_preset_import_done )
929989
990+ def import_library_preset_payload (self , preset_name : str , payload : dict [str , object ]) -> None :
991+ write_mini_eq_preset_file (preset_path_for_name (preset_name ), payload )
992+ self .controller .apply_preset_payload (payload )
993+ self .selected_band_index = None
994+ self .set_visible_band_count (fader_band_count_for_profile (self .controller .bands ))
995+ self .current_preset_name = preset_name
996+ self .saved_preset_signature = self .controller .state_signature ()
997+ self .set_curve_revert_baseline (preset_name )
998+ self .refresh_preset_list ()
999+ self .sync_ui_from_state ()
1000+ self .set_status (f"Imported Preset: { preset_name } " )
1001+ self .notify_control_presets_changed ()
1002+ self .notify_control_state_changed ()
1003+
9301004 def on_preset_import_done (self , dialog : Gtk .FileDialog , result : Gio .AsyncResult ) -> None :
9311005 try :
9321006 file = dialog .open_finish (result )
@@ -947,18 +1021,15 @@ def on_preset_import_done(self, dialog: Gtk.FileDialog, result: Gio.AsyncResult)
9471021 stored_payload = dict (payload )
9481022 stored_payload ["version" ] = PRESET_VERSION
9491023 stored_payload ["name" ] = preset_name
950- write_mini_eq_preset_file (preset_path_for_name (preset_name ), stored_payload )
951- self .controller .apply_preset_payload (stored_payload )
952- self .selected_band_index = None
953- self .set_visible_band_count (fader_band_count_for_profile (self .controller .bands ))
954- self .current_preset_name = preset_name
955- self .saved_preset_signature = self .controller .state_signature ()
956- self .set_curve_revert_baseline (preset_name )
957- self .refresh_preset_list ()
958- self .sync_ui_from_state ()
959- self .set_status (f"Imported Preset: { preset_name } " )
960- self .notify_control_presets_changed ()
961- self .notify_control_state_changed ()
1024+ if self .preset_name_exists (preset_name ):
1025+ self .confirm_preset_replacement (
1026+ preset_name ,
1027+ f"{ preset_name } already exists. Replace it with the imported preset?" ,
1028+ lambda : self .import_library_preset_payload (preset_name , stored_payload ),
1029+ )
1030+ return
1031+
1032+ self .import_library_preset_payload (preset_name , stored_payload )
9621033 except Exception as exc :
9631034 self .set_status (str (exc ))
9641035
0 commit comments