mirror of
				https://github.com/johrpan/musicus.git
				synced 2025-10-26 11:47:25 +01:00 
			
		
		
		
	Add recording editor
This commit is contained in:
		
							parent
							
								
									c3e7663be9
								
							
						
					
					
						commit
						bd3a61c4bf
					
				
					 5 changed files with 386 additions and 3 deletions
				
			
		|  | @ -9,6 +9,7 @@ | ||||||
|         <file preprocess="xml-stripblanks">ui/performance_editor.ui</file> |         <file preprocess="xml-stripblanks">ui/performance_editor.ui</file> | ||||||
|         <file preprocess="xml-stripblanks">ui/person_editor.ui</file> |         <file preprocess="xml-stripblanks">ui/person_editor.ui</file> | ||||||
|         <file preprocess="xml-stripblanks">ui/person_selector.ui</file> |         <file preprocess="xml-stripblanks">ui/person_selector.ui</file> | ||||||
|  |         <file preprocess="xml-stripblanks">ui/recording_editor.ui</file> | ||||||
|         <file preprocess="xml-stripblanks">ui/section_editor.ui</file> |         <file preprocess="xml-stripblanks">ui/section_editor.ui</file> | ||||||
|         <file preprocess="xml-stripblanks">ui/window.ui</file> |         <file preprocess="xml-stripblanks">ui/window.ui</file> | ||||||
|         <file preprocess="xml-stripblanks">ui/work_editor.ui</file> |         <file preprocess="xml-stripblanks">ui/work_editor.ui</file> | ||||||
|  |  | ||||||
							
								
								
									
										231
									
								
								res/ui/recording_editor.ui
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								res/ui/recording_editor.ui
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,231 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!-- Generated with glade 3.38.1 --> | ||||||
|  | <interface> | ||||||
|  |   <requires lib="gtk+" version="3.22"/> | ||||||
|  |   <object class="GtkWindow" id="window"> | ||||||
|  |     <property name="can-focus">False</property> | ||||||
|  |     <property name="modal">True</property> | ||||||
|  |     <property name="default-width">500</property> | ||||||
|  |     <property name="default-height">450</property> | ||||||
|  |     <property name="destroy-with-parent">True</property> | ||||||
|  |     <property name="type-hint">dialog</property> | ||||||
|  |     <child> | ||||||
|  |       <object class="GtkNotebook"> | ||||||
|  |         <property name="visible">True</property> | ||||||
|  |         <property name="can-focus">True</property> | ||||||
|  |         <child> | ||||||
|  |           <!-- n-columns=2 n-rows=2 --> | ||||||
|  |           <object class="GtkGrid"> | ||||||
|  |             <property name="visible">True</property> | ||||||
|  |             <property name="can-focus">False</property> | ||||||
|  |             <property name="border-width">18</property> | ||||||
|  |             <property name="row-spacing">12</property> | ||||||
|  |             <property name="column-spacing">6</property> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkLabel"> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">False</property> | ||||||
|  |                 <property name="halign">end</property> | ||||||
|  |                 <property name="label" translatable="yes">Comment</property> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="left-attach">0</property> | ||||||
|  |                 <property name="top-attach">1</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkButton" id="work_button"> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">True</property> | ||||||
|  |                 <property name="receives-default">True</property> | ||||||
|  |                 <property name="hexpand">True</property> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkLabel" id="work_label"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">False</property> | ||||||
|  |                     <property name="halign">start</property> | ||||||
|  |                     <property name="label" translatable="yes">Select …</property> | ||||||
|  |                   </object> | ||||||
|  |                 </child> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="left-attach">1</property> | ||||||
|  |                 <property name="top-attach">0</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkEntry" id="comment_button"> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">True</property> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="left-attach">1</property> | ||||||
|  |                 <property name="top-attach">1</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkLabel"> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">False</property> | ||||||
|  |                 <property name="halign">end</property> | ||||||
|  |                 <property name="label" translatable="yes">Work</property> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="left-attach">0</property> | ||||||
|  |                 <property name="top-attach">0</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |           </object> | ||||||
|  |         </child> | ||||||
|  |         <child type="tab"> | ||||||
|  |           <object class="GtkLabel"> | ||||||
|  |             <property name="visible">True</property> | ||||||
|  |             <property name="can-focus">False</property> | ||||||
|  |             <property name="label" translatable="yes">Overview</property> | ||||||
|  |           </object> | ||||||
|  |           <packing> | ||||||
|  |             <property name="tab-fill">False</property> | ||||||
|  |           </packing> | ||||||
|  |         </child> | ||||||
|  |         <child> | ||||||
|  |           <object class="GtkBox"> | ||||||
|  |             <property name="visible">True</property> | ||||||
|  |             <property name="can-focus">False</property> | ||||||
|  |             <property name="border-width">18</property> | ||||||
|  |             <property name="spacing">6</property> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkScrolledWindow"> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">True</property> | ||||||
|  |                 <property name="shadow-type">in</property> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkViewport"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">False</property> | ||||||
|  |                     <child> | ||||||
|  |                       <object class="GtkListBox" id="performer_list"> | ||||||
|  |                         <property name="visible">True</property> | ||||||
|  |                         <property name="can-focus">False</property> | ||||||
|  |                         <property name="hexpand">True</property> | ||||||
|  |                         <property name="vexpand">True</property> | ||||||
|  |                         <child type="placeholder"> | ||||||
|  |                           <object class="GtkLabel"> | ||||||
|  |                             <property name="visible">True</property> | ||||||
|  |                             <property name="can-focus">False</property> | ||||||
|  |                             <property name="label" translatable="yes">No performers added.</property> | ||||||
|  |                           </object> | ||||||
|  |                         </child> | ||||||
|  |                       </object> | ||||||
|  |                     </child> | ||||||
|  |                   </object> | ||||||
|  |                 </child> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="expand">True</property> | ||||||
|  |                 <property name="fill">True</property> | ||||||
|  |                 <property name="position">0</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkBox"> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">False</property> | ||||||
|  |                 <property name="border-width">0</property> | ||||||
|  |                 <property name="orientation">vertical</property> | ||||||
|  |                 <property name="spacing">6</property> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkButton" id="add_performer_button"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">True</property> | ||||||
|  |                     <property name="receives-default">True</property> | ||||||
|  |                     <child> | ||||||
|  |                       <object class="GtkImage"> | ||||||
|  |                         <property name="visible">True</property> | ||||||
|  |                         <property name="can-focus">False</property> | ||||||
|  |                         <property name="icon-name">list-add-symbolic</property> | ||||||
|  |                       </object> | ||||||
|  |                     </child> | ||||||
|  |                   </object> | ||||||
|  |                   <packing> | ||||||
|  |                     <property name="expand">False</property> | ||||||
|  |                     <property name="fill">True</property> | ||||||
|  |                     <property name="position">0</property> | ||||||
|  |                   </packing> | ||||||
|  |                 </child> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkButton" id="remove_performer_button"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">True</property> | ||||||
|  |                     <property name="receives-default">True</property> | ||||||
|  |                     <child> | ||||||
|  |                       <object class="GtkImage"> | ||||||
|  |                         <property name="visible">True</property> | ||||||
|  |                         <property name="can-focus">False</property> | ||||||
|  |                         <property name="icon-name">list-remove-symbolic</property> | ||||||
|  |                       </object> | ||||||
|  |                     </child> | ||||||
|  |                   </object> | ||||||
|  |                   <packing> | ||||||
|  |                     <property name="expand">False</property> | ||||||
|  |                     <property name="fill">True</property> | ||||||
|  |                     <property name="position">1</property> | ||||||
|  |                   </packing> | ||||||
|  |                 </child> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="expand">False</property> | ||||||
|  |                 <property name="fill">True</property> | ||||||
|  |                 <property name="position">1</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |           </object> | ||||||
|  |           <packing> | ||||||
|  |             <property name="position">1</property> | ||||||
|  |           </packing> | ||||||
|  |         </child> | ||||||
|  |         <child type="tab"> | ||||||
|  |           <object class="GtkLabel"> | ||||||
|  |             <property name="visible">True</property> | ||||||
|  |             <property name="can-focus">False</property> | ||||||
|  |             <property name="label" translatable="yes">Performers</property> | ||||||
|  |           </object> | ||||||
|  |           <packing> | ||||||
|  |             <property name="position">1</property> | ||||||
|  |             <property name="tab-fill">False</property> | ||||||
|  |           </packing> | ||||||
|  |         </child> | ||||||
|  |       </object> | ||||||
|  |     </child> | ||||||
|  |     <child type="titlebar"> | ||||||
|  |       <object class="GtkHeaderBar"> | ||||||
|  |         <property name="visible">True</property> | ||||||
|  |         <property name="can-focus">False</property> | ||||||
|  |         <property name="title" translatable="yes">Recording</property> | ||||||
|  |         <child> | ||||||
|  |           <object class="GtkButton" id="cancel_button"> | ||||||
|  |             <property name="label" translatable="yes">Cancel</property> | ||||||
|  |             <property name="visible">True</property> | ||||||
|  |             <property name="can-focus">True</property> | ||||||
|  |             <property name="receives-default">True</property> | ||||||
|  |           </object> | ||||||
|  |         </child> | ||||||
|  |         <child> | ||||||
|  |           <object class="GtkButton" id="save_button"> | ||||||
|  |             <property name="label" translatable="yes">Save</property> | ||||||
|  |             <property name="visible">True</property> | ||||||
|  |             <property name="sensitive">False</property> | ||||||
|  |             <property name="can-focus">True</property> | ||||||
|  |             <property name="receives-default">True</property> | ||||||
|  |             <style> | ||||||
|  |               <class name="suggested-action"/> | ||||||
|  |             </style> | ||||||
|  |           </object> | ||||||
|  |           <packing> | ||||||
|  |             <property name="pack-type">end</property> | ||||||
|  |             <property name="position">1</property> | ||||||
|  |           </packing> | ||||||
|  |         </child> | ||||||
|  |       </object> | ||||||
|  |     </child> | ||||||
|  |   </object> | ||||||
|  | </interface> | ||||||
|  | @ -22,6 +22,9 @@ pub use person_editor::*; | ||||||
| pub mod person_selector; | pub mod person_selector; | ||||||
| pub use person_selector::*; | pub use person_selector::*; | ||||||
| 
 | 
 | ||||||
|  | pub mod recording_editor; | ||||||
|  | pub use recording_editor::*; | ||||||
|  | 
 | ||||||
| pub mod section_editor; | pub mod section_editor; | ||||||
| pub use section_editor::*; | pub use section_editor::*; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										142
									
								
								src/dialogs/recording_editor.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								src/dialogs/recording_editor.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,142 @@ | ||||||
|  | use super::*; | ||||||
|  | use crate::backend::Backend; | ||||||
|  | use crate::database::*; | ||||||
|  | use glib::clone; | ||||||
|  | use gtk::prelude::*; | ||||||
|  | use gtk_macros::get_widget; | ||||||
|  | use std::cell::RefCell; | ||||||
|  | use std::rc::Rc; | ||||||
|  | use std::convert::TryInto; | ||||||
|  | 
 | ||||||
|  | pub struct RecordingEditor<F> | ||||||
|  | where | ||||||
|  |     F: Fn(RecordingDescription) -> () + 'static, | ||||||
|  | { | ||||||
|  |     backend: Rc<Backend>, | ||||||
|  |     window: gtk::Window, | ||||||
|  |     callback: F, | ||||||
|  |     id: i64, | ||||||
|  |     save_button: gtk::Button, | ||||||
|  |     work_label: gtk::Label, | ||||||
|  |     work: RefCell<Option<WorkDescription>>, | ||||||
|  |     performers: RefCell<Vec<PerformanceDescription>>, | ||||||
|  |     performer_list: gtk::ListBox, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<F> RecordingEditor<F> | ||||||
|  | where | ||||||
|  |     F: Fn(RecordingDescription) -> () + 'static, | ||||||
|  | { | ||||||
|  |     pub fn new<P: IsA<gtk::Window>>( | ||||||
|  |         backend: Rc<Backend>, | ||||||
|  |         parent: &P, | ||||||
|  |         recording: Option<RecordingDescription>, | ||||||
|  |         callback: F, | ||||||
|  |     ) -> Rc<Self> { | ||||||
|  |         let builder = | ||||||
|  |             gtk::Builder::from_resource("/de/johrpan/musicus_editor/ui/recording_editor.ui"); | ||||||
|  | 
 | ||||||
|  |         get_widget!(builder, gtk::Window, window); | ||||||
|  |         get_widget!(builder, gtk::Button, cancel_button); | ||||||
|  |         get_widget!(builder, gtk::Button, save_button); | ||||||
|  |         get_widget!(builder, gtk::Button, work_button); | ||||||
|  |         get_widget!(builder, gtk::Label, work_label); | ||||||
|  |         get_widget!(builder, gtk::ListBox, performer_list); | ||||||
|  |         get_widget!(builder, gtk::Button, add_performer_button); | ||||||
|  |         get_widget!(builder, gtk::Button, remove_performer_button); | ||||||
|  | 
 | ||||||
|  |         let (id, work, performers) = match recording { | ||||||
|  |             Some(recording) => { | ||||||
|  |                 save_button.set_sensitive(true); | ||||||
|  |                 (recording.id, Some(recording.work), recording.performances) | ||||||
|  |             } | ||||||
|  |             None => (rand::random::<u32>().into(), None, Vec::new()), | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         let result = Rc::new(RecordingEditor { | ||||||
|  |             backend: backend, | ||||||
|  |             window: window, | ||||||
|  |             callback: callback, | ||||||
|  |             id: id, | ||||||
|  |             save_button: save_button, | ||||||
|  |             work_label: work_label, | ||||||
|  |             work: RefCell::new(work), | ||||||
|  |             performers: RefCell::new(performers), | ||||||
|  |             performer_list: performer_list, | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         cancel_button.connect_clicked(clone!(@strong result => move |_| { | ||||||
|  |             result.window.close(); | ||||||
|  |         })); | ||||||
|  | 
 | ||||||
|  |         result | ||||||
|  |             .save_button | ||||||
|  |             .connect_clicked(clone!(@strong result => move |_| { | ||||||
|  |                 result.window.close(); | ||||||
|  |             })); | ||||||
|  | 
 | ||||||
|  |         work_button.connect_clicked(clone!(@strong result => move |_| { | ||||||
|  |             WorkSelector::new(result.backend.clone(), &result.window, clone!(@strong result => move |work| { | ||||||
|  |                 result.work.replace(Some(work.clone())); | ||||||
|  |                 result.work_label.set_text(&format!("{}: {}", work.composer.name_fl(), work.title)); | ||||||
|  |                 result.save_button.set_sensitive(true); | ||||||
|  |             })).show(); | ||||||
|  |         })); | ||||||
|  | 
 | ||||||
|  |         add_performer_button.connect_clicked(clone!(@strong result => move |_| { | ||||||
|  |             PerformanceEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |performance| { | ||||||
|  |                 { | ||||||
|  |                     let mut performers = result.performers.borrow_mut(); | ||||||
|  |                     performers.push(performance); | ||||||
|  |                 } | ||||||
|  |                 
 | ||||||
|  |                 result.show_performers(); | ||||||
|  |             })).show(); | ||||||
|  |         })); | ||||||
|  | 
 | ||||||
|  |         remove_performer_button.connect_clicked(clone!(@strong result => move |_| { | ||||||
|  |             let row = result.get_selected_performer_row(); | ||||||
|  |             match row { | ||||||
|  |                 Some(row) => { | ||||||
|  |                     let index = row.get_index(); | ||||||
|  |                     let index: usize = index.try_into().unwrap(); | ||||||
|  |                     result.performers.borrow_mut().remove(index); | ||||||
|  |                     result.show_performers(); | ||||||
|  |                 } | ||||||
|  |                 None => (), | ||||||
|  |             } | ||||||
|  |         })); | ||||||
|  | 
 | ||||||
|  |         result.window.set_transient_for(Some(parent)); | ||||||
|  | 
 | ||||||
|  |         result | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn show(&self) { | ||||||
|  |         self.window.show(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn show_performers(&self) { | ||||||
|  |         for child in self.performer_list.get_children() { | ||||||
|  |             self.performer_list.remove(&child); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (index, performer) in self.performers.borrow().iter().enumerate() { | ||||||
|  |             let label = gtk::Label::new(Some(&performer.get_title())); | ||||||
|  |             label.set_halign(gtk::Align::Start); | ||||||
|  |             let row = SelectorRow::new(index.try_into().unwrap(), &label); | ||||||
|  |             row.show_all(); | ||||||
|  |             self.performer_list.insert(&row, -1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_selected_performer_row(&self) -> Option<SelectorRow> { | ||||||
|  |         match self.performer_list.get_selected_rows().first() { | ||||||
|  |             Some(row) => match row.get_child() { | ||||||
|  |                 Some(child) => Some(child.downcast().unwrap()), | ||||||
|  |                 None => None, | ||||||
|  |             }, | ||||||
|  |             None => None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -124,9 +124,15 @@ impl Window { | ||||||
|             }) |             }) | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         action!(result.window, "add-recording", |_, _| { |         action!( | ||||||
|             println!("TODO: Add recording."); |             result.window, | ||||||
|         }); |             "add-recording", | ||||||
|  |             clone!(@strong result => move |_, _| { | ||||||
|  |                 RecordingEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |_| { | ||||||
|  |                     result.clone().set_state(Loading); | ||||||
|  |                 })).show(); | ||||||
|  |             }) | ||||||
|  |         ); | ||||||
| 
 | 
 | ||||||
|         action!( |         action!( | ||||||
|             result.window, |             result.window, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Elias Projahn
						Elias Projahn