11use crate :: {
22 cli:: Arguments ,
3- recipe:: { export_recipe, Recipe , WidgetMetadata } ,
3+ recipe:: { export_recipe, parse_recipe , Recipe , WidgetMetadata } ,
44} ;
55use std:: {
66 fs:: File , io:: Write ,
@@ -10,6 +10,7 @@ use std::{
1010use copypasta:: { ClipboardContext , ClipboardProvider } ;
1111use eframe:: egui;
1212use winit:: raw_window_handle:: HasWindowHandle ;
13+ use indexmap:: map:: IndexMap ;
1314
1415struct SmApp {
1516 first_frame : bool ,
@@ -19,13 +20,17 @@ struct SmApp {
1920 metadata : WidgetMetadata ,
2021 selected_files : Vec < PathBuf > ,
2122 show_confirmation_dialog : bool ,
23+ show_merge_dialog : bool ,
24+ staging_merge : Option < ( Recipe , IndexMap < String , IndexMap < String , bool > > ) > ,
2225 allowed_to_close : bool ,
2326 show_about : bool ,
2427 args : Arguments ,
2528 start_rendering : bool ,
2629 // yeah that's the damn typename
2730 recipe_saved : String ,
28- sender : Sender < ( Recipe , Arguments , Option < windows:: Win32 :: Foundation :: HWND > ) >
31+ sender : Sender < ( Recipe , Arguments , Option < windows:: Win32 :: Foundation :: HWND > ) > ,
32+ make_new_recipe : bool ,
33+ new_recipe_filename : String ,
2934}
3035
3136pub const WINDOW_NAME : & str = "smoothie-app" ;
@@ -41,7 +46,7 @@ pub fn save_recipe(recipe: &Recipe, recipe_filename: &PathBuf, metadata: &Widget
4146 None => panic ! ( "Could not resolve Smoothie's binary directory `{exe:?}`" ) ,
4247 } ;
4348
44- let recipe_path = if PathBuf :: from ( recipe_filename. clone ( ) ) . exists ( ) {
49+ let recipe_path = if recipe_filename. clone ( ) . exists ( ) {
4550 PathBuf :: from ( recipe_filename)
4651 } else {
4752 let cur_dir_rc = bin_dir. join ( recipe_filename) ;
@@ -73,6 +78,7 @@ pub fn save_recipe(recipe: &Recipe, recipe_filename: &PathBuf, metadata: &Widget
7378 println ! ( "{}" , & content) ;
7479}
7580
81+ #[ allow( clippy:: extra_unused_lifetimes) ]
7682pub fn sm_gui < ' gui > (
7783 recipe : Recipe ,
7884 metadata : WidgetMetadata ,
@@ -91,13 +97,16 @@ pub fn sm_gui<'gui>(
9197 ..Default :: default ( )
9298 } ;
9399
100+
94101 eframe:: run_native (
95102 WINDOW_NAME ,
96103 options,
97104 Box :: new ( |_cc|{
98105
99106 Ok ( Box :: new (
100107 SmApp {
108+ show_merge_dialog : false ,
109+ staging_merge : None ,
101110 first_frame : true ,
102111 save_new_recipe : false ,
103112 recipe_change_request : None ,
@@ -110,7 +119,9 @@ pub fn sm_gui<'gui>(
110119 show_about : false ,
111120 args,
112121 start_rendering : false ,
113- sender : sender
122+ sender,
123+ make_new_recipe : false ,
124+ new_recipe_filename : String :: new ( ) ,
114125 }
115126 ) )
116127 } ) ,
@@ -160,6 +171,7 @@ impl eframe::App for SmApp {
160171 // self.allowed_to_close = true;
161172 ui. ctx ( ) . send_viewport_cmd ( egui:: ViewportCommand :: Close ) ;
162173 }
174+
163175 let ctrl_s = egui:: KeyboardShortcut {
164176 modifiers : egui:: Modifiers {
165177 ctrl : true ,
@@ -172,6 +184,19 @@ impl eframe::App for SmApp {
172184 } ;
173185 let ctrl_s_pressed = ctx. input_mut ( |i| i. consume_shortcut ( & ctrl_s) ) ;
174186
187+ let ctrl_p = egui:: KeyboardShortcut {
188+ modifiers : egui:: Modifiers {
189+ ctrl : true ,
190+ alt : false ,
191+ shift : false ,
192+ mac_cmd : false ,
193+ command : false ,
194+ } ,
195+ logical_key : egui:: Key :: P ,
196+ } ;
197+ let ctrl_p_pressed = ctx. input_mut ( |i| i. consume_shortcut ( & ctrl_p) ) ;
198+
199+
175200 egui:: menu:: bar ( ui, |ui| {
176201 egui:: widgets:: global_theme_preference_switch ( ui) ;
177202 if ui. button ( "README" ) . clicked ( ) {
@@ -257,14 +282,14 @@ impl eframe::App for SmApp {
257282 ctx. set_contents ( recipe_txt) . unwrap ( ) ;
258283 }
259284 } ) ;
260- egui:: menu:: bar ( ui, |ui| {
285+ // egui::menu::bar(ui, |ui| {
261286
262- let binding = PathBuf :: from ( self . args . recipe . clone ( ) ) ;
263- let selected_recipe = binding
264- . file_name ( ) . expect ( "Failed unwrapping file name from args.recipe" )
265- . to_str ( ) . expect ( "Failed unwrapping string from filename from args.recipe" ) ;
287+ let binding = PathBuf :: from ( self . args . recipe . clone ( ) ) ;
288+ let selected_recipe = binding
289+ . file_name ( ) . expect ( "Failed unwrapping file name from args.recipe" )
290+ . to_str ( ) . expect ( "Failed unwrapping string from filename from args.recipe" ) ;
266291
267- egui:: ComboBox :: from_label ( "" )
292+ egui:: ComboBox :: from_label ( "" )
268293 . selected_text ( selected_recipe)
269294 . show_ui ( ui, |ui| {
270295 let enum_values = crate :: portable:: get_config_filepaths ( ) ;
@@ -281,16 +306,21 @@ impl eframe::App for SmApp {
281306 selected_value,
282307 enum_value. file_name ( ) . to_owned ( ) . unwrap ( ) . to_str ( ) . unwrap ( )
283308 ) ;
309+
284310 }
285- if binding. to_str ( ) . unwrap ( ) . to_string ( ) != self . args . recipe {
311+ if binding. to_str ( ) . unwrap ( ) != self . args . recipe . as_str ( ) {
286312 self . recipe_change_request = Some ( binding. to_str ( ) . unwrap ( ) . to_string ( ) ) ;
287313 // let (recipe, metadata) = crate::recipe::get_recipe(&mut self.args);
288314 // self.recipe = recipe;
289315 // self.metadata = metadata;
290316 }
291-
317+ ui. selectable_value (
318+ & mut self . make_new_recipe ,
319+ true ,
320+ "New recipe"
321+ ) ;
292322 } ) ;
293- } ) ;
323+ // });
294324 egui:: menu:: bar ( ui, |_| { } ) ; // <br>
295325 egui:: ScrollArea :: vertical ( ) . show ( ui, |ui| {
296326 for cat in & mut self . metadata . keys ( ) {
@@ -320,7 +350,7 @@ impl eframe::App for SmApp {
320350 & cat. clone( ) . replace( " " , "-" )
321351 ) ;
322352
323- let _ = if ui. hyperlink_to ( cat, & url) . secondary_clicked ( ) {
353+ if ui. hyperlink_to ( cat, & url) . secondary_clicked ( ) {
324354 dbg ! ( & url) ;
325355 println ! ( "Copied `{}` to clipboard" , & url) ;
326356 let mut ctx = ClipboardContext :: new ( ) . unwrap ( ) ;
@@ -469,7 +499,7 @@ impl eframe::App for SmApp {
469499 . to_ascii_lowercase ( )
470500 . as_os_str ( )
471501 . to_str ( )
472- . expect ( "Failed " ) ,
502+ . expect ( "Failed convertin file extension to string " ) ,
473503 ) {
474504 self . selected_files . push ( path)
475505 } else {
@@ -489,6 +519,150 @@ impl eframe::App for SmApp {
489519 }
490520 } ) ;
491521
522+ if self . make_new_recipe {
523+ let mut open = true ;
524+ egui:: Window :: new ( "new recipe" ) . open ( & mut open) . show ( ctx, |ui|{
525+ ui. label ( format ! ( "it will use current recipe ({}) as base" , selected_recipe) ) ;
526+ ui. horizontal ( |ui| {
527+ ui. label ( "file name: " ) ;
528+ ui. add ( egui:: TextEdit :: singleline ( & mut self . new_recipe_filename ) . desired_width ( 200.0 ) ) . request_focus ( ) ;
529+ ui. label ( ".ini" )
530+ } ) ;
531+ if ui. button ( "create" ) . clicked ( ) {
532+ }
533+ } ) ;
534+ if !open {
535+ self . make_new_recipe = false ;
536+ }
537+ }
538+
539+ if ctrl_p_pressed {
540+ let clipboard = ClipboardContext :: new ( ) . unwrap ( ) . get_contents ( ) . expect ( "Failed reading system clipboard" ) ;
541+ let lines = clipboard. split ( "\n " ) ;
542+ let mut cleaned: Vec < String > = vec ! [ ] ;
543+
544+ #[ allow( non_camel_case_types) ]
545+ enum _RecipeTypes {
546+ smoothie_rs,
547+ smoothie_py,
548+ teres,
549+ blur_18,
550+ blur_19,
551+ blur_20,
552+ }
553+
554+ for line in lines {
555+ if line. is_empty ( ) || line. starts_with ( "#" ) || line. starts_with ( "//" ) || line. starts_with ( ";" ) {
556+ continue
557+ }
558+ cleaned. push ( line. to_owned ( ) ) ;
559+ } ;
560+
561+ if !cleaned. is_empty ( ) {
562+ let mut to_merge = Recipe :: new ( ) ;
563+
564+ parse_recipe (
565+ PathBuf :: from ( self . args . recipe . clone ( ) ) ,
566+ Some ( cleaned. join ( "\n " ) ) , & mut to_merge,
567+ & mut None ,
568+ false
569+ ) ;
570+
571+ let mut toggled: IndexMap < String , IndexMap < String , bool > > = IndexMap :: new ( ) ;
572+
573+ for section in to_merge. keys ( ) {
574+ toggled. insert ( section. to_owned ( ) , IndexMap :: new ( ) ) ;
575+ }
576+
577+ for section in toggled. to_owned ( ) . keys ( ) {
578+ for key in to_merge. get_section ( section) {
579+ toggled
580+ . entry ( section. to_owned ( ) )
581+ . or_default ( )
582+ . insert ( key. 0 . to_owned ( ) , true ) ;
583+ }
584+ }
585+
586+ self . staging_merge = Some ( ( to_merge, toggled) ) ;
587+ self . show_merge_dialog = true ;
588+ }
589+
590+ }
591+
592+ if self . show_merge_dialog {
593+
594+ egui:: Window :: new ( "merge pasted config" ) . show ( ctx, |ui|{
595+
596+ let mut cancel = false ;
597+ let mut merge = false ;
598+ let mut invert_selection = false ;
599+ ui. horizontal ( |ui| {
600+ cancel = ui. button ( "cancel" ) . clicked ( ) ;
601+ merge = ui. button ( "merge" ) . clicked ( ) ;
602+ invert_selection = ui. button ( "invert" ) . clicked ( ) ;
603+ } ) ;
604+ let staging_recipe = self . staging_merge . as_mut ( ) . unwrap ( ) ;
605+ for section in staging_recipe. 0 . to_owned ( ) . keys ( ) {
606+
607+ ui. horizontal ( |ui| {
608+
609+ let section_selection: Vec < bool > = staging_recipe. 1 . entry ( section. to_owned ( ) ) . or_default ( ) . values ( ) . cloned ( ) . collect ( ) ;
610+
611+ let mut select = !section_selection. contains ( & false ) ;
612+
613+ let toggle_section = ui. checkbox ( & mut select, section) ;
614+
615+ let section = staging_recipe. 1 . entry ( section. to_owned ( ) ) . or_default ( ) ;
616+
617+
618+ for ( key, value) in section. to_owned ( ) . into_iter ( ) {
619+
620+ if toggle_section. clicked ( ) {
621+ section. insert ( key. to_owned ( ) , select) ;
622+ } else if invert_selection {
623+
624+ section. insert ( key. to_owned ( ) , !value) ;
625+ }
626+ }
627+ } ) ;
628+
629+ for ( key , value) in staging_recipe. 0 . get_section_mut ( section) {
630+
631+ ui. horizontal ( |ui| {
632+
633+ let enabled = staging_recipe. 1
634+ . entry ( section. to_owned ( ) )
635+ . or_default ( )
636+ . entry ( key. to_owned ( ) )
637+ . or_insert ( false ) ;
638+
639+ ui. checkbox ( enabled, key) ;
640+ * enabled = enabled. to_owned ( ) ;
641+ ui. add ( egui:: TextEdit :: singleline ( & mut * value) ) ;
642+ } ) ;
643+ }
644+ }
645+ if merge {
646+
647+ self . show_merge_dialog = false ;
648+ for section in staging_recipe. 0 . to_owned ( ) . keys ( ) {
649+ for ( key, value) in staging_recipe. 0 . get_section ( section) {
650+ let enabled =
651+ staging_recipe. 1 . entry ( section. to_owned ( ) ) . or_default ( ) . entry ( key. to_owned ( ) ) . or_insert ( false ) ;
652+
653+ if !enabled. to_owned ( ) { continue }
654+ self . recipe . insert_value ( section, key. to_owned ( ) , value. to_owned ( ) ) ;
655+ }
656+ }
657+
658+ }
659+ if cancel || merge {
660+ self . staging_merge = None ;
661+ self . show_merge_dialog = false ;
662+ }
663+ } ) ;
664+ }
665+
492666 if self . show_about {
493667 egui:: Window :: new ( "about smoothie app" )
494668 . collapsible ( false )
@@ -570,7 +744,7 @@ impl eframe::App for SmApp {
570744 // the recipe isn't formatted yet, let it go through a frame
571745 // to normalize bools and int slider increments
572746 //self.recipe_saved = format!("{:?}", recipe);
573- self . save_new_recipe ;
747+ // self.save_new_recipe;
574748 }
575749 if ui. button ( "Don't Save" ) . clicked ( ) {
576750 self . recipe_change_request = None ;
0 commit comments