/[svn]/gigedit/trunk/src/gigedit/mainwindow.cpp
ViewVC logotype

Annotation of /gigedit/trunk/src/gigedit/mainwindow.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1582 - (hide annotations) (download)
Sat Dec 8 12:28:53 2007 UTC (16 years, 3 months ago) by persson
File size: 63771 byte(s)
* fixed file properties dialog - properties can now be edited

1 schoenebeck 1225 /*
2     * Copyright (C) 2006, 2007 Andreas Persson
3     *
4     * This program is free software; you can redistribute it and/or
5     * modify it under the terms of the GNU General Public License as
6     * published by the Free Software Foundation; either version 2, or (at
7     * your option) any later version.
8     *
9     * This program is distributed in the hope that it will be useful, but
10     * WITHOUT ANY WARRANTY; without even the implied warranty of
11     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12     * General Public License for more details.
13     *
14     * You should have received a copy of the GNU General Public License
15     * along with program; see the file COPYING. If not, write to the Free
16     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17     * 02110-1301 USA.
18     */
19    
20     #include <iostream>
21    
22     #include <gtkmm/filechooserdialog.h>
23     #include <gtkmm/messagedialog.h>
24     #include <gtkmm/stock.h>
25     #include <gtkmm/targetentry.h>
26     #include <gtkmm/main.h>
27 schoenebeck 1415 #include <gtkmm/toggleaction.h>
28 schoenebeck 1225
29 schoenebeck 1396 #include "global.h"
30    
31 persson 1261 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
32 schoenebeck 1225 #define ABOUT_DIALOG
33     #include <gtkmm/aboutdialog.h>
34     #endif
35    
36 persson 1303 #if (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION < 6) || GLIBMM_MAJOR_VERSION < 2
37     namespace Glib {
38     Glib::ustring filename_display_basename(const std::string& filename)
39     {
40     gchar* gstr = g_path_get_basename(filename.c_str());
41     Glib::ustring str(gstr);
42     g_free(gstr);
43     return Glib::filename_to_utf8(str);
44     }
45     }
46     #endif
47    
48 schoenebeck 1225 #include <stdio.h>
49     #include <sndfile.h>
50    
51     #include "mainwindow.h"
52    
53 schoenebeck 1411 #include "../../gfx/status_attached.xpm"
54     #include "../../gfx/status_detached.xpm"
55    
56 schoenebeck 1225 template<class T> inline std::string ToString(T o) {
57     std::stringstream ss;
58     ss << o;
59     return ss.str();
60     }
61    
62 persson 1582 Table::Table(int x, int y) : Gtk::Table(x, y), rowno(0) { }
63    
64     void Table::add(BoolEntry& boolentry)
65     {
66     attach(boolentry.widget, 0, 2, rowno, rowno + 1,
67     Gtk::FILL, Gtk::SHRINK);
68     rowno++;
69     }
70    
71     void Table::add(BoolEntryPlus6& boolentry)
72     {
73     attach(boolentry.widget, 0, 2, rowno, rowno + 1,
74     Gtk::FILL, Gtk::SHRINK);
75     rowno++;
76     }
77    
78     void Table::add(LabelWidget& prop)
79     {
80     attach(prop.label, 1, 2, rowno, rowno + 1,
81     Gtk::FILL, Gtk::SHRINK);
82     attach(prop.widget, 2, 3, rowno, rowno + 1,
83     Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK);
84     rowno++;
85     }
86    
87 persson 1533 MainWindow::MainWindow() :
88     dimreg_label(_("Changes apply to:")),
89     dimreg_all_regions(_("all regions")),
90     dimreg_all_dimregs(_("all dimension splits")),
91     dimreg_stereo(_("both channels"))
92 schoenebeck 1225 {
93     // set_border_width(5);
94     // set_default_size(400, 200);
95    
96    
97     add(m_VBox);
98    
99     // Handle selection
100     Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
101     tree_sel_ref->signal_changed().connect(
102     sigc::mem_fun(*this, &MainWindow::on_sel_change));
103    
104     // m_TreeView.set_reorderable();
105    
106     m_TreeView.signal_button_press_event().connect_notify(
107     sigc::mem_fun(*this, &MainWindow::on_button_release));
108    
109     // Add the TreeView tab, inside a ScrolledWindow, with the button underneath:
110     m_ScrolledWindow.add(m_TreeView);
111     // m_ScrolledWindow.set_size_request(200, 600);
112     m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
113    
114     m_ScrolledWindowSamples.add(m_TreeViewSamples);
115     m_ScrolledWindowSamples.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
116    
117    
118     m_TreeViewNotebook.set_size_request(300);
119    
120     m_HPaned.add1(m_TreeViewNotebook);
121 persson 1533 dimreg_hbox.add(dimreg_label);
122     dimreg_hbox.add(dimreg_all_regions);
123     dimreg_hbox.add(dimreg_all_dimregs);
124     dimreg_stereo.set_active();
125     dimreg_hbox.add(dimreg_stereo);
126     dimreg_vbox.add(dimreg_edit);
127 persson 1582 dimreg_vbox.pack_start(dimreg_hbox, Gtk::PACK_SHRINK);
128 persson 1533 m_HPaned.add2(dimreg_vbox);
129 schoenebeck 1225
130    
131     m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");
132     m_TreeViewNotebook.append_page(m_ScrolledWindow, "Instruments");
133    
134    
135     actionGroup = Gtk::ActionGroup::create();
136    
137     actionGroup->add(Gtk::Action::create("MenuFile", _("_File")));
138     actionGroup->add(Gtk::Action::create("New", Gtk::Stock::NEW),
139     sigc::mem_fun(
140     *this, &MainWindow::on_action_file_new));
141     Glib::RefPtr<Gtk::Action> action =
142     Gtk::Action::create("Open", Gtk::Stock::OPEN);
143     action->property_label() = action->property_label() + "...";
144     actionGroup->add(action,
145     sigc::mem_fun(
146     *this, &MainWindow::on_action_file_open));
147     actionGroup->add(Gtk::Action::create("Save", Gtk::Stock::SAVE),
148     sigc::mem_fun(
149     *this, &MainWindow::on_action_file_save));
150     action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS);
151     action->property_label() = action->property_label() + "...";
152     actionGroup->add(action,
153 persson 1261 Gtk::AccelKey("<shift><control>s"),
154 schoenebeck 1225 sigc::mem_fun(
155 persson 1261 *this, &MainWindow::on_action_file_save_as));
156 schoenebeck 1225 actionGroup->add(Gtk::Action::create("Properties",
157     Gtk::Stock::PROPERTIES),
158     sigc::mem_fun(
159     *this, &MainWindow::on_action_file_properties));
160     actionGroup->add(Gtk::Action::create("InstrProperties",
161     Gtk::Stock::PROPERTIES),
162     sigc::mem_fun(
163     *this, &MainWindow::show_instr_props));
164     actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),
165     sigc::mem_fun(
166 persson 1261 *this, &MainWindow::on_action_quit));
167 schoenebeck 1225 actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));
168    
169 schoenebeck 1415 actionGroup->add(Gtk::Action::create("MenuView", _("_View")));
170     Glib::RefPtr<Gtk::ToggleAction> toggle_action =
171     Gtk::ToggleAction::create("Statusbar", _("_Statusbar"));
172     toggle_action->set_active(true);
173     actionGroup->add(toggle_action,
174     sigc::mem_fun(
175     *this, &MainWindow::on_action_view_status_bar));
176    
177 schoenebeck 1225 action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);
178     actionGroup->add(Gtk::Action::create("MenuHelp",
179     action->property_label()));
180     #ifdef ABOUT_DIALOG
181     actionGroup->add(Gtk::Action::create("About", Gtk::Stock::ABOUT),
182     sigc::mem_fun(
183     *this, &MainWindow::on_action_help_about));
184     #endif
185     actionGroup->add(
186     Gtk::Action::create("AddInstrument", _("Add _Instrument")),
187     sigc::mem_fun(*this, &MainWindow::on_action_add_instrument)
188     );
189     actionGroup->add(
190     Gtk::Action::create("RemoveInstrument", Gtk::Stock::REMOVE),
191     sigc::mem_fun(*this, &MainWindow::on_action_remove_instrument)
192     );
193    
194     // sample right-click popup actions
195     actionGroup->add(
196     Gtk::Action::create("SampleProperties", Gtk::Stock::PROPERTIES),
197     sigc::mem_fun(*this, &MainWindow::on_action_sample_properties)
198     );
199     actionGroup->add(
200     Gtk::Action::create("AddGroup", _("Add _Group")),
201     sigc::mem_fun(*this, &MainWindow::on_action_add_group)
202     );
203     actionGroup->add(
204     Gtk::Action::create("AddSample", _("Add _Sample(s)")),
205     sigc::mem_fun(*this, &MainWindow::on_action_add_sample)
206     );
207     actionGroup->add(
208     Gtk::Action::create("RemoveSample", Gtk::Stock::REMOVE),
209     sigc::mem_fun(*this, &MainWindow::on_action_remove_sample)
210     );
211    
212     uiManager = Gtk::UIManager::create();
213     uiManager->insert_action_group(actionGroup);
214 persson 1261 add_accel_group(uiManager->get_accel_group());
215 schoenebeck 1225
216     Glib::ustring ui_info =
217     "<ui>"
218     " <menubar name='MenuBar'>"
219     " <menu action='MenuFile'>"
220     " <menuitem action='New'/>"
221     " <menuitem action='Open'/>"
222     " <separator/>"
223     " <menuitem action='Save'/>"
224     " <menuitem action='SaveAs'/>"
225     " <separator/>"
226     " <menuitem action='Properties'/>"
227     " <separator/>"
228     " <menuitem action='Quit'/>"
229     " </menu>"
230     " <menu action='MenuInstrument'>"
231     " </menu>"
232 schoenebeck 1415 " <menu action='MenuView'>"
233     " <menuitem action='Statusbar'/>"
234     " </menu>"
235 schoenebeck 1225 #ifdef ABOUT_DIALOG
236     " <menu action='MenuHelp'>"
237     " <menuitem action='About'/>"
238     " </menu>"
239     #endif
240     " </menubar>"
241     " <popup name='PopupMenu'>"
242     " <menuitem action='InstrProperties'/>"
243     " <menuitem action='AddInstrument'/>"
244     " <separator/>"
245     " <menuitem action='RemoveInstrument'/>"
246     " </popup>"
247     " <popup name='SamplePopupMenu'>"
248     " <menuitem action='SampleProperties'/>"
249     " <menuitem action='AddGroup'/>"
250     " <menuitem action='AddSample'/>"
251     " <separator/>"
252     " <menuitem action='RemoveSample'/>"
253     " </popup>"
254     "</ui>";
255     uiManager->add_ui_from_string(ui_info);
256    
257     popup_menu = dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/PopupMenu"));
258    
259     Gtk::Widget* menuBar = uiManager->get_widget("/MenuBar");
260     m_VBox.pack_start(*menuBar, Gtk::PACK_SHRINK);
261     m_VBox.pack_start(m_HPaned);
262     m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
263     m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
264 schoenebeck 1411 m_VBox.pack_start(m_StatusBar, Gtk::PACK_SHRINK);
265 schoenebeck 1225
266 schoenebeck 1411 // Status Bar:
267     m_StatusBar.pack_start(m_AttachedStateLabel, Gtk::PACK_SHRINK);
268     m_StatusBar.pack_start(m_AttachedStateImage, Gtk::PACK_SHRINK);
269     m_StatusBar.show();
270    
271 persson 1261 m_RegionChooser.signal_region_selected().connect(
272 schoenebeck 1225 sigc::mem_fun(*this, &MainWindow::region_changed) );
273 persson 1261 m_DimRegionChooser.signal_dimregion_selected().connect(
274 schoenebeck 1225 sigc::mem_fun(*this, &MainWindow::dimreg_changed) );
275    
276    
277     // Create the Tree model:
278     m_refTreeModel = Gtk::ListStore::create(m_Columns);
279     m_TreeView.set_model(m_refTreeModel);
280     m_refTreeModel->signal_row_changed().connect(
281     sigc::mem_fun(*this, &MainWindow::instrument_name_changed)
282     );
283    
284     // Add the TreeView's view columns:
285     m_TreeView.append_column_editable("Instrument", m_Columns.m_col_name);
286     m_TreeView.set_headers_visible(false);
287    
288     // create samples treeview (including its data model)
289     m_refSamplesTreeModel = SamplesTreeStore::create(m_SamplesModel);
290     m_TreeViewSamples.set_model(m_refSamplesTreeModel);
291     // m_TreeViewSamples.set_reorderable();
292     m_TreeViewSamples.append_column_editable("Samples", m_SamplesModel.m_col_name);
293     m_TreeViewSamples.set_headers_visible(false);
294     m_TreeViewSamples.signal_button_press_event().connect_notify(
295     sigc::mem_fun(*this, &MainWindow::on_sample_treeview_button_release)
296     );
297     m_refSamplesTreeModel->signal_row_changed().connect(
298     sigc::mem_fun(*this, &MainWindow::sample_name_changed)
299     );
300    
301     // establish drag&drop between samples tree view and dimension region 'Sample' text entry
302     std::list<Gtk::TargetEntry> drag_target_gig_sample;
303     drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
304     m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
305 persson 1303 m_TreeViewSamples.signal_drag_begin().connect(
306     sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)
307     );
308 schoenebeck 1225 m_TreeViewSamples.signal_drag_data_get().connect(
309     sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
310     );
311     dimreg_edit.wSample->drag_dest_set(drag_target_gig_sample);
312     dimreg_edit.wSample->signal_drag_data_received().connect(
313     sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
314     );
315 persson 1261 dimreg_edit.signal_dimreg_changed().connect(
316 schoenebeck 1322 sigc::hide(sigc::mem_fun(*this, &MainWindow::file_changed)));
317 persson 1261 m_RegionChooser.signal_instrument_changed().connect(
318     sigc::mem_fun(*this, &MainWindow::file_changed));
319     m_DimRegionChooser.signal_region_changed().connect(
320     sigc::mem_fun(*this, &MainWindow::file_changed));
321     instrumentProps.signal_instrument_changed().connect(
322     sigc::mem_fun(*this, &MainWindow::file_changed));
323 persson 1582 propDialog.signal_info_changed().connect(
324     sigc::mem_fun(*this, &MainWindow::file_changed));
325 schoenebeck 1322
326     dimreg_edit.signal_dimreg_to_be_changed().connect(
327     dimreg_to_be_changed_signal.make_slot());
328     dimreg_edit.signal_dimreg_changed().connect(
329     dimreg_changed_signal.make_slot());
330     dimreg_edit.signal_sample_ref_changed().connect(
331     sample_ref_changed_signal.make_slot());
332    
333     m_RegionChooser.signal_instrument_struct_to_be_changed().connect(
334     sigc::hide(
335     sigc::bind(
336     file_structure_to_be_changed_signal.make_slot(),
337     sigc::ref(this->file)
338     )
339     )
340     );
341     m_RegionChooser.signal_instrument_struct_changed().connect(
342     sigc::hide(
343     sigc::bind(
344     file_structure_changed_signal.make_slot(),
345     sigc::ref(this->file)
346     )
347     )
348     );
349     m_RegionChooser.signal_region_to_be_changed().connect(
350     region_to_be_changed_signal.make_slot());
351     m_RegionChooser.signal_region_changed_signal().connect(
352     region_changed_signal.make_slot());
353    
354 persson 1533 dimreg_all_regions.signal_toggled().connect(
355     sigc::mem_fun(*this, &MainWindow::update_dimregs));
356     dimreg_all_dimregs.signal_toggled().connect(
357     sigc::mem_fun(*this, &MainWindow::dimreg_all_dimregs_toggled));
358     dimreg_stereo.signal_toggled().connect(
359     sigc::mem_fun(*this, &MainWindow::update_dimregs));
360    
361 schoenebeck 1225 file = 0;
362 persson 1261 file_is_changed = false;
363 schoenebeck 1411 set_file_is_shared(false);
364 schoenebeck 1225
365     show_all_children();
366 schoenebeck 1300
367     // start with a new gig file by default
368     on_action_file_new();
369 schoenebeck 1225 }
370    
371     MainWindow::~MainWindow()
372     {
373     }
374    
375 persson 1261 bool MainWindow::on_delete_event(GdkEventAny* event)
376     {
377 schoenebeck 1382 return !file_is_shared && file_is_changed && !close_confirmation_dialog();
378 persson 1261 }
379    
380     void MainWindow::on_action_quit()
381     {
382 schoenebeck 1382 if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
383 persson 1261 hide();
384     }
385    
386 schoenebeck 1225 void MainWindow::region_changed()
387     {
388     m_DimRegionChooser.set_region(m_RegionChooser.get_region());
389     }
390    
391 persson 1533 gig::Instrument* MainWindow::get_instrument()
392 schoenebeck 1225 {
393 persson 1533 gig::Instrument* instrument = 0;
394 schoenebeck 1225 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
395    
396     Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
397     if (it) {
398     Gtk::TreeModel::Row row = *it;
399 persson 1533 instrument = row[m_Columns.m_col_instr];
400     }
401     return instrument;
402     }
403 schoenebeck 1225
404 persson 1533 void MainWindow::add_region_to_dimregs(gig::Region* region, bool stereo, bool all_dimregs)
405     {
406     if (all_dimregs) {
407     for (int i = 0 ; i < region->DimensionRegions ; i++) {
408     if (region->pDimensionRegions[i]) {
409     dimreg_edit.dimregs.insert(region->pDimensionRegions[i]);
410     }
411     }
412 schoenebeck 1225 } else {
413 persson 1533 m_DimRegionChooser.get_dimregions(region, stereo, dimreg_edit.dimregs);
414 schoenebeck 1225 }
415     }
416    
417 persson 1533 void MainWindow::update_dimregs()
418     {
419     dimreg_edit.dimregs.clear();
420     bool all_regions = dimreg_all_regions.get_active();
421     bool stereo = dimreg_stereo.get_active();
422     bool all_dimregs = dimreg_all_dimregs.get_active();
423    
424     if (all_regions) {
425     gig::Instrument* instrument = get_instrument();
426     if (instrument) {
427     for (gig::Region* region = instrument->GetFirstRegion() ;
428     region ;
429     region = instrument->GetNextRegion()) {
430     add_region_to_dimregs(region, stereo, all_dimregs);
431     }
432     }
433     } else {
434     gig::Region* region = m_RegionChooser.get_region();
435     if (region) {
436     add_region_to_dimregs(region, stereo, all_dimregs);
437     }
438     }
439     }
440    
441     void MainWindow::dimreg_all_dimregs_toggled()
442     {
443     dimreg_stereo.set_sensitive(!dimreg_all_dimregs.get_active());
444     update_dimregs();
445     }
446    
447     void MainWindow::dimreg_changed()
448     {
449     update_dimregs();
450     dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());
451     }
452    
453     void MainWindow::on_sel_change()
454     {
455     m_RegionChooser.set_instrument(get_instrument());
456     }
457    
458 schoenebeck 1225 void loader_progress_callback(gig::progress_t* progress)
459     {
460     Loader* loader = static_cast<Loader*>(progress->custom);
461     loader->progress_callback(progress->factor);
462     }
463    
464     void Loader::progress_callback(float fraction)
465     {
466     {
467     Glib::Mutex::Lock lock(progressMutex);
468     progress = fraction;
469     }
470     progress_dispatcher();
471     }
472    
473     void Loader::thread_function()
474     {
475     printf("thread_function self=%x\n", Glib::Thread::self());
476     printf("Start %s\n", filename);
477     RIFF::File* riff = new RIFF::File(filename);
478     gig = new gig::File(riff);
479     gig::progress_t progress;
480     progress.callback = loader_progress_callback;
481     progress.custom = this;
482    
483     gig->GetInstrument(0, &progress);
484     printf("End\n");
485     finished_dispatcher();
486     }
487    
488     Loader::Loader(const char* filename)
489     : thread(0), filename(filename)
490     {
491     }
492    
493     void Loader::launch()
494     {
495     thread = Glib::Thread::create(sigc::mem_fun(*this, &Loader::thread_function), true);
496     printf("launch thread=%x\n", thread);
497     }
498    
499     float Loader::get_progress()
500     {
501     float res;
502     {
503     Glib::Mutex::Lock lock(progressMutex);
504     res = progress;
505     }
506     return res;
507     }
508    
509     Glib::Dispatcher& Loader::signal_progress()
510     {
511     return progress_dispatcher;
512     }
513    
514     Glib::Dispatcher& Loader::signal_finished()
515     {
516     return finished_dispatcher;
517     }
518    
519     LoadDialog::LoadDialog(const Glib::ustring& title, Gtk::Window& parent)
520     : Gtk::Dialog(title, parent, true)
521     {
522     get_vbox()->pack_start(progressBar);
523     show_all_children();
524     }
525    
526     // Clear all GUI elements / controls. This method is typically called
527     // before a new .gig file is to be created or to be loaded.
528     void MainWindow::__clear() {
529     // remove all entries from "Instrument" menu
530     Gtk::MenuItem* instrument_menu =
531     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
532     instrument_menu->hide();
533     for (int i = 0; i < instrument_menu->get_submenu()->items().size(); i++) {
534     delete &instrument_menu->get_submenu()->items()[i];
535     }
536     instrument_menu->get_submenu()->items().clear();
537     // forget all samples that ought to be imported
538     m_SampleImportQueue.clear();
539     // clear the samples and instruments tree views
540     m_refTreeModel->clear();
541     m_refSamplesTreeModel->clear();
542     // free libgig's gig::File instance
543 schoenebeck 1382 if (file && !file_is_shared) delete file;
544     file = NULL;
545 schoenebeck 1411 set_file_is_shared(false);
546 schoenebeck 1225 }
547    
548     void MainWindow::on_action_file_new()
549     {
550 schoenebeck 1382 if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
551 persson 1261
552 schoenebeck 1382 if (file_is_shared && !leaving_shared_mode_dialog()) return;
553    
554 schoenebeck 1225 // clear all GUI elements
555     __clear();
556     // create a new .gig file (virtually yet)
557     gig::File* pFile = new gig::File;
558     // already add one new instrument by default
559     gig::Instrument* pInstrument = pFile->AddInstrument();
560     pInstrument->pInfo->Name = "Unnamed Instrument";
561     // update GUI with that new gig::File
562 persson 1261 load_gig(pFile, 0 /*no file name yet*/);
563 schoenebeck 1225 }
564    
565 persson 1261 bool MainWindow::close_confirmation_dialog()
566     {
567     gchar* msg = g_strdup_printf(_("Save changes to \"%s\" before closing?"),
568     Glib::filename_display_basename(filename).c_str());
569     Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
570     g_free(msg);
571 persson 1303 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
572 persson 1261 dialog.set_secondary_text(_("If you close without saving, your changes will be lost."));
573 persson 1303 #endif
574 persson 1261 dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
575     dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
576     dialog.add_button(file_has_name ? Gtk::Stock::SAVE : Gtk::Stock::SAVE_AS, Gtk::RESPONSE_YES);
577     dialog.set_default_response(Gtk::RESPONSE_YES);
578     int response = dialog.run();
579 persson 1303 dialog.hide();
580 persson 1261 if (response == Gtk::RESPONSE_YES) return file_save();
581     return response != Gtk::RESPONSE_CANCEL;
582     }
583    
584 schoenebeck 1382 bool MainWindow::leaving_shared_mode_dialog() {
585     Glib::ustring msg = _("Detach from sampler and proceed working stand-alone?");
586     Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
587     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
588     dialog.set_secondary_text(
589     _("If you proceed to work on another instrument file, it won't be "
590     "used by the sampler until you tell the sampler explicitly to "
591     "load it.")
592     );
593     #endif
594     dialog.add_button(_("_Yes, Detach"), Gtk::RESPONSE_YES);
595     dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
596     dialog.set_default_response(Gtk::RESPONSE_CANCEL);
597     int response = dialog.run();
598     dialog.hide();
599     return response == Gtk::RESPONSE_YES;
600     }
601    
602 schoenebeck 1225 void MainWindow::on_action_file_open()
603     {
604 schoenebeck 1382 if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
605 persson 1261
606 schoenebeck 1382 if (file_is_shared && !leaving_shared_mode_dialog()) return;
607    
608 schoenebeck 1225 Gtk::FileChooserDialog dialog(*this, _("Open file"));
609     dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
610     dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
611 persson 1261 dialog.set_default_response(Gtk::RESPONSE_OK);
612 schoenebeck 1225 Gtk::FileFilter filter;
613     filter.add_pattern("*.gig");
614     dialog.set_filter(filter);
615 persson 1261 if (current_dir != "") {
616     dialog.set_current_folder(current_dir);
617     }
618 schoenebeck 1225 if (dialog.run() == Gtk::RESPONSE_OK) {
619 persson 1261 std::string filename = dialog.get_filename();
620     printf("filename=%s\n", filename.c_str());
621 schoenebeck 1225 printf("on_action_file_open self=%x\n", Glib::Thread::self());
622 persson 1261 load_file(filename.c_str());
623     current_dir = Glib::path_get_dirname(filename);
624 schoenebeck 1225 }
625     }
626    
627     void MainWindow::load_file(const char* name)
628     {
629 persson 1303 __clear();
630 schoenebeck 1225 load_dialog = new LoadDialog("Loading...", *this);
631     load_dialog->show_all();
632     loader = new Loader(strdup(name));
633     loader->signal_progress().connect(
634     sigc::mem_fun(*this, &MainWindow::on_loader_progress));
635     loader->signal_finished().connect(
636     sigc::mem_fun(*this, &MainWindow::on_loader_finished));
637     loader->launch();
638     }
639    
640     void MainWindow::load_instrument(gig::Instrument* instr) {
641     if (!instr) {
642     Glib::ustring txt = "Provided instrument is NULL!\n";
643     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
644     msg.run();
645     Gtk::Main::quit();
646     }
647 schoenebeck 1328 // clear all GUI elements
648     __clear();
649     // load the instrument
650 schoenebeck 1225 gig::File* pFile = (gig::File*) instr->GetParent();
651 schoenebeck 1382 load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);
652 schoenebeck 1225 //TODO: automatically select the given instrument
653     }
654    
655     void MainWindow::on_loader_progress()
656     {
657     load_dialog->set_fraction(loader->get_progress());
658     }
659    
660     void MainWindow::on_loader_finished()
661     {
662     printf("Loader finished!\n");
663     printf("on_loader_finished self=%x\n", Glib::Thread::self());
664     load_gig(loader->gig, loader->filename);
665     load_dialog->hide();
666     }
667    
668     void MainWindow::on_action_file_save()
669     {
670 persson 1261 file_save();
671     }
672    
673 persson 1303 bool MainWindow::check_if_savable()
674     {
675     if (!file) return false;
676    
677     if (!file->GetFirstSample()) {
678     Gtk::MessageDialog(*this, _("The file could not be saved "
679     "because it contains no samples"),
680     false, Gtk::MESSAGE_ERROR).run();
681     return false;
682     }
683    
684     for (gig::Instrument* instrument = file->GetFirstInstrument() ; instrument ;
685     instrument = file->GetNextInstrument()) {
686     if (!instrument->GetFirstRegion()) {
687     Gtk::MessageDialog(*this, _("The file could not be saved "
688     "because there are instruments "
689     "that have no regions"),
690     false, Gtk::MESSAGE_ERROR).run();
691     return false;
692     }
693     }
694     return true;
695     }
696    
697 persson 1261 bool MainWindow::file_save()
698     {
699 persson 1303 if (!check_if_savable()) return false;
700 schoenebeck 1382 if (!file_is_shared && !file_has_name) return file_save_as();
701 persson 1261
702 schoenebeck 1225 std::cout << "Saving file\n" << std::flush;
703 schoenebeck 1322 file_structure_to_be_changed_signal.emit(this->file);
704 schoenebeck 1225 try {
705     file->Save();
706 persson 1261 if (file_is_changed) {
707     set_title(get_title().substr(1));
708     file_is_changed = false;
709     }
710 schoenebeck 1225 } catch (RIFF::Exception e) {
711 schoenebeck 1322 file_structure_changed_signal.emit(this->file);
712 schoenebeck 1382 Glib::ustring txt = _("Could not save file: ") + e.Message;
713 schoenebeck 1225 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
714     msg.run();
715 persson 1261 return false;
716 schoenebeck 1225 }
717     std::cout << "Saving file done\n" << std::flush;
718     __import_queued_samples();
719 schoenebeck 1322 file_structure_changed_signal.emit(this->file);
720 persson 1261 return true;
721 schoenebeck 1225 }
722    
723     void MainWindow::on_action_file_save_as()
724     {
725 persson 1303 if (!check_if_savable()) return;
726 persson 1261 file_save_as();
727     }
728    
729     bool MainWindow::file_save_as()
730     {
731     Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);
732 schoenebeck 1225 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
733     dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
734 persson 1261 dialog.set_default_response(Gtk::RESPONSE_OK);
735    
736     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 8) || GTKMM_MAJOR_VERSION > 2
737     dialog.set_do_overwrite_confirmation();
738     // TODO: an overwrite dialog for gtkmm < 2.8
739     #endif
740 schoenebeck 1225 Gtk::FileFilter filter;
741     filter.add_pattern("*.gig");
742     dialog.set_filter(filter);
743 persson 1261
744     if (Glib::path_is_absolute(filename)) {
745     dialog.set_filename(filename);
746     } else if (current_dir != "") {
747     dialog.set_current_folder(current_dir);
748     }
749     dialog.set_current_name(Glib::filename_display_basename(filename));
750    
751 schoenebeck 1225 if (dialog.run() == Gtk::RESPONSE_OK) {
752 schoenebeck 1322 file_structure_to_be_changed_signal.emit(this->file);
753 schoenebeck 1225 try {
754 persson 1261 std::string filename = dialog.get_filename();
755     if (!Glib::str_has_suffix(filename, ".gig")) {
756     filename += ".gig";
757     }
758     printf("filename=%s\n", filename.c_str());
759     file->Save(filename);
760     this->filename = filename;
761     current_dir = Glib::path_get_dirname(filename);
762     set_title(Glib::filename_display_basename(filename));
763     file_has_name = true;
764     file_is_changed = false;
765 schoenebeck 1225 } catch (RIFF::Exception e) {
766 schoenebeck 1322 file_structure_changed_signal.emit(this->file);
767 schoenebeck 1382 Glib::ustring txt = _("Could not save file: ") + e.Message;
768 schoenebeck 1225 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
769     msg.run();
770 persson 1261 return false;
771 schoenebeck 1225 }
772     __import_queued_samples();
773 schoenebeck 1322 file_structure_changed_signal.emit(this->file);
774 persson 1261 return true;
775 schoenebeck 1225 }
776 persson 1261 return false;
777 schoenebeck 1225 }
778    
779     // actually write the sample(s)' data to the gig file
780     void MainWindow::__import_queued_samples() {
781     std::cout << "Starting sample import\n" << std::flush;
782     Glib::ustring error_files;
783     printf("Samples to import: %d\n", m_SampleImportQueue.size());
784     for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
785     iter != m_SampleImportQueue.end(); ) {
786     printf("Importing sample %s\n",(*iter).sample_path.c_str());
787     SF_INFO info;
788     info.format = 0;
789     SNDFILE* hFile = sf_open((*iter).sample_path.c_str(), SFM_READ, &info);
790     try {
791     if (!hFile) throw std::string("could not open file");
792     // determine sample's bit depth
793     int bitdepth;
794     switch (info.format & 0xff) {
795     case SF_FORMAT_PCM_S8:
796     case SF_FORMAT_PCM_16:
797 persson 1265 case SF_FORMAT_PCM_U8:
798 schoenebeck 1225 bitdepth = 16;
799     break;
800     case SF_FORMAT_PCM_24:
801     case SF_FORMAT_PCM_32:
802     case SF_FORMAT_FLOAT:
803     case SF_FORMAT_DOUBLE:
804 persson 1265 bitdepth = 24;
805 schoenebeck 1225 break;
806     default:
807     sf_close(hFile); // close sound file
808     throw std::string("format not supported"); // unsupported subformat (yet?)
809     }
810 persson 1265
811     const int bufsize = 10000;
812 schoenebeck 1225 switch (bitdepth) {
813 persson 1265 case 16: {
814     short* buffer = new short[bufsize * info.channels];
815     sf_count_t cnt = info.frames;
816     while (cnt) {
817     // libsndfile does the conversion for us (if needed)
818     int n = sf_readf_short(hFile, buffer, bufsize);
819     // write from buffer directly (physically) into .gig file
820     iter->gig_sample->Write(buffer, n);
821     cnt -= n;
822     }
823     delete[] buffer;
824 schoenebeck 1225 break;
825 persson 1265 }
826     case 24: {
827     int* srcbuf = new int[bufsize * info.channels];
828     uint8_t* dstbuf = new uint8_t[bufsize * 3 * info.channels];
829     sf_count_t cnt = info.frames;
830     while (cnt) {
831     // libsndfile returns 32 bits, convert to 24
832     int n = sf_readf_int(hFile, srcbuf, bufsize);
833     int j = 0;
834     for (int i = 0 ; i < n * info.channels ; i++) {
835     dstbuf[j++] = srcbuf[i] >> 8;
836     dstbuf[j++] = srcbuf[i] >> 16;
837     dstbuf[j++] = srcbuf[i] >> 24;
838     }
839     // write from buffer directly (physically) into .gig file
840     iter->gig_sample->Write(dstbuf, n);
841     cnt -= n;
842     }
843     delete[] srcbuf;
844     delete[] dstbuf;
845 schoenebeck 1225 break;
846 persson 1265 }
847 schoenebeck 1225 }
848     // cleanup
849     sf_close(hFile);
850     // on success we remove the sample from the import queue,
851     // otherwise keep it, maybe it works the next time ?
852     std::list<SampleImportItem>::iterator cur = iter;
853     ++iter;
854     m_SampleImportQueue.erase(cur);
855     } catch (std::string what) {
856     // remember the files that made trouble (and their cause)
857     if (error_files.size()) error_files += "\n";
858     error_files += (*iter).sample_path += " (" + what + ")";
859     ++iter;
860     }
861     }
862     // show error message box when some sample(s) could not be imported
863     if (error_files.size()) {
864 schoenebeck 1382 Glib::ustring txt = _("Could not import the following sample(s):\n") + error_files;
865 schoenebeck 1225 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
866     msg.run();
867     }
868     }
869    
870     void MainWindow::on_action_file_properties()
871     {
872     propDialog.show();
873     propDialog.deiconify();
874     }
875    
876     void MainWindow::on_action_help_about()
877     {
878     #ifdef ABOUT_DIALOG
879     Gtk::AboutDialog dialog;
880     dialog.set_version(VERSION);
881 schoenebeck 1436 dialog.set_copyright("Copyright (C) 2006,2007 Andreas Persson");
882     dialog.set_comments(
883     "Released under the GNU General Public License.\n"
884     "\n"
885     "Please notice that this is still a very young instrument editor. "
886     "So better backup your Gigasampler files before editing them with "
887     "this application.\n"
888     "\n"
889     "Please report bugs to: http://bugs.linuxsampler.org"
890     );
891     dialog.set_website("http://www.linuxsampler.org");
892     dialog.set_website_label("http://www.linuxsampler.org");
893 schoenebeck 1225 dialog.run();
894     #endif
895     }
896    
897     PropDialog::PropDialog()
898 persson 1582 : table(2,1),
899     eName("Name"),
900     eCreationDate("Creation date"),
901     eComments("Comments"),
902     eProduct("Product"),
903     eCopyright("Copyright"),
904     eArtists("Artists"),
905     eGenre("Genre"),
906     eKeywords("Keywords"),
907     eEngineer("Engineer"),
908     eTechnician("Technician"),
909     eSoftware("Software"),
910     eMedium("Medium"),
911     eSource("Source"),
912     eSourceForm("Source form"),
913     eCommissioned("Commissioned"),
914     eSubject("Subject"),
915     quitButton(Gtk::Stock::CLOSE),
916     update_model(0)
917 schoenebeck 1225 {
918 persson 1582 set_title("File Properties");
919     eName.set_width_chars(50);
920    
921     connect(eName, &DLS::Info::Name);
922     connect(eCreationDate, &DLS::Info::CreationDate);
923     connect(eComments, &DLS::Info::Comments);
924     connect(eProduct, &DLS::Info::Product);
925     connect(eCopyright, &DLS::Info::Copyright);
926     connect(eArtists, &DLS::Info::Artists);
927     connect(eGenre, &DLS::Info::Genre);
928     connect(eKeywords, &DLS::Info::Keywords);
929     connect(eEngineer, &DLS::Info::Engineer);
930     connect(eTechnician, &DLS::Info::Technician);
931     connect(eSoftware, &DLS::Info::Software);
932     connect(eMedium, &DLS::Info::Medium);
933     connect(eSource, &DLS::Info::Source);
934     connect(eSourceForm, &DLS::Info::SourceForm);
935     connect(eCommissioned, &DLS::Info::Commissioned);
936     connect(eSubject, &DLS::Info::Subject);
937    
938     table.add(eName);
939     table.add(eCreationDate);
940     table.add(eComments);
941     table.add(eProduct);
942     table.add(eCopyright);
943     table.add(eArtists);
944     table.add(eGenre);
945     table.add(eKeywords);
946     table.add(eEngineer);
947     table.add(eTechnician);
948     table.add(eSoftware);
949     table.add(eMedium);
950     table.add(eSource);
951     table.add(eSourceForm);
952     table.add(eCommissioned);
953     table.add(eSubject);
954    
955 schoenebeck 1225 table.set_col_spacings(5);
956 persson 1582 add(vbox);
957     table.set_border_width(5);
958     vbox.add(table);
959     vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
960     buttonBox.set_layout(Gtk::BUTTONBOX_END);
961     buttonBox.set_border_width(5);
962     buttonBox.show();
963     buttonBox.pack_start(quitButton);
964     quitButton.set_flags(Gtk::CAN_DEFAULT);
965     quitButton.grab_focus();
966     quitButton.signal_clicked().connect(
967     sigc::mem_fun(*this, &PropDialog::hide));
968 schoenebeck 1225
969 persson 1582 quitButton.show();
970     vbox.show();
971 schoenebeck 1225 show_all_children();
972     }
973    
974     void PropDialog::set_info(DLS::Info* info)
975     {
976 persson 1582 this->info = info;
977     update_model++;
978     eName.set_value(info->Name);
979     eCreationDate.set_value(info->CreationDate);
980     eComments.set_value(info->Comments);
981     eProduct.set_value(info->Product);
982     eCopyright.set_value(info->Copyright);
983     eArtists.set_value(info->Artists);
984     eGenre.set_value(info->Genre);
985     eKeywords.set_value(info->Keywords);
986     eEngineer.set_value(info->Engineer);
987     eTechnician.set_value(info->Technician);
988     eSoftware.set_value(info->Software);
989     eMedium.set_value(info->Medium);
990     eSource.set_value(info->Source);
991     eSourceForm.set_value(info->SourceForm);
992     eCommissioned.set_value(info->Commissioned);
993     eSubject.set_value(info->Subject);
994     update_model--;
995 schoenebeck 1225 }
996    
997 persson 1582 sigc::signal<void>& PropDialog::signal_info_changed()
998     {
999     return info_changed;
1000     }
1001    
1002 persson 1460 void InstrumentProps::set_IsDrum(bool value)
1003     {
1004     instrument->IsDrum = value;
1005     }
1006    
1007     void InstrumentProps::set_MIDIBank(uint16_t value)
1008     {
1009     instrument->MIDIBank = value;
1010     }
1011    
1012     void InstrumentProps::set_MIDIProgram(uint32_t value)
1013     {
1014     instrument->MIDIProgram = value;
1015     }
1016    
1017     void InstrumentProps::set_DimensionKeyRange_low(uint8_t value)
1018     {
1019     instrument->DimensionKeyRange.low = value;
1020     if (value > instrument->DimensionKeyRange.high) {
1021     eDimensionKeyRangeHigh.set_value(value);
1022     }
1023     }
1024    
1025     void InstrumentProps::set_DimensionKeyRange_high(uint8_t value)
1026     {
1027     instrument->DimensionKeyRange.high = value;
1028     if (value < instrument->DimensionKeyRange.low) {
1029     eDimensionKeyRangeLow.set_value(value);
1030     }
1031     }
1032    
1033 schoenebeck 1225 InstrumentProps::InstrumentProps()
1034     : table(2,1),
1035     quitButton(Gtk::Stock::CLOSE),
1036     eName("Name"),
1037 persson 1262 eIsDrum("Is drum"),
1038     eMIDIBank("MIDI bank", 0, 16383),
1039     eMIDIProgram("MIDI program"),
1040 schoenebeck 1225 eAttenuation("Attenuation", 0, 96, 0, 1),
1041     eGainPlus6("Gain +6dB", eAttenuation, -6),
1042 persson 1262 eEffectSend("Effect send", 0, 65535),
1043     eFineTune("Fine tune", -8400, 8400),
1044     ePitchbendRange("Pitchbend range", 0, 12),
1045     ePianoReleaseMode("Piano release mode"),
1046     eDimensionKeyRangeLow("Dimension key range low"),
1047 persson 1460 eDimensionKeyRangeHigh("Dimension key range high"),
1048     update_model(0)
1049 schoenebeck 1225 {
1050 persson 1582 set_title("Instrument Properties");
1051 schoenebeck 1225
1052 persson 1460 connect(eIsDrum, &InstrumentProps::set_IsDrum);
1053     connect(eMIDIBank, &InstrumentProps::set_MIDIBank);
1054     connect(eMIDIProgram, &InstrumentProps::set_MIDIProgram);
1055     connect(eAttenuation, &gig::Instrument::Attenuation);
1056     connect(eGainPlus6, &gig::Instrument::Attenuation);
1057     connect(eEffectSend, &gig::Instrument::EffectSend);
1058     connect(eFineTune, &gig::Instrument::FineTune);
1059     connect(ePitchbendRange, &gig::Instrument::PitchbendRange);
1060     connect(ePianoReleaseMode, &gig::Instrument::PianoReleaseMode);
1061     connect(eDimensionKeyRangeLow,
1062     &InstrumentProps::set_DimensionKeyRange_low);
1063     connect(eDimensionKeyRangeHigh,
1064     &InstrumentProps::set_DimensionKeyRange_high);
1065    
1066 schoenebeck 1225 table.set_col_spacings(5);
1067    
1068 persson 1582 table.add(eName);
1069     table.add(eIsDrum);
1070     table.add(eMIDIBank);
1071     table.add(eMIDIProgram);
1072     table.add(eAttenuation);
1073     table.add(eGainPlus6);
1074     table.add(eEffectSend);
1075     table.add(eFineTune);
1076     table.add(ePitchbendRange);
1077     table.add(ePianoReleaseMode);
1078     table.add(eDimensionKeyRangeLow);
1079     table.add(eDimensionKeyRangeHigh);
1080 schoenebeck 1225
1081     add(vbox);
1082     table.set_border_width(5);
1083     vbox.pack_start(table);
1084     table.show();
1085     vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
1086     buttonBox.set_layout(Gtk::BUTTONBOX_END);
1087     buttonBox.set_border_width(5);
1088     buttonBox.show();
1089     buttonBox.pack_start(quitButton);
1090     quitButton.set_flags(Gtk::CAN_DEFAULT);
1091     quitButton.grab_focus();
1092    
1093     quitButton.signal_clicked().connect(
1094     sigc::mem_fun(*this, &InstrumentProps::hide));
1095    
1096     quitButton.show();
1097     vbox.show();
1098     show_all_children();
1099     }
1100    
1101     void InstrumentProps::set_instrument(gig::Instrument* instrument)
1102     {
1103 persson 1460 this->instrument = instrument;
1104    
1105     update_model++;
1106 persson 1582 eName.set_value(instrument->pInfo->Name);
1107 persson 1460 eIsDrum.set_value(instrument->IsDrum);
1108     eMIDIBank.set_value(instrument->MIDIBank);
1109     eMIDIProgram.set_value(instrument->MIDIProgram);
1110     eAttenuation.set_value(instrument->Attenuation);
1111     eGainPlus6.set_value(instrument->Attenuation);
1112     eEffectSend.set_value(instrument->EffectSend);
1113     eFineTune.set_value(instrument->FineTune);
1114     ePitchbendRange.set_value(instrument->PitchbendRange);
1115     ePianoReleaseMode.set_value(instrument->PianoReleaseMode);
1116     eDimensionKeyRangeLow.set_value(instrument->DimensionKeyRange.low);
1117     eDimensionKeyRangeHigh.set_value(instrument->DimensionKeyRange.high);
1118     update_model--;
1119 schoenebeck 1225 }
1120    
1121 schoenebeck 1339 sigc::signal<void>& InstrumentProps::signal_instrument_changed()
1122 schoenebeck 1225 {
1123 persson 1261 return instrument_changed;
1124     }
1125 schoenebeck 1225
1126 persson 1261 void MainWindow::file_changed()
1127     {
1128     if (file && !file_is_changed) {
1129     set_title("*" + get_title());
1130     file_is_changed = true;
1131 schoenebeck 1225 }
1132 persson 1261 }
1133 schoenebeck 1225
1134 schoenebeck 1382 void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)
1135 persson 1261 {
1136     file = 0;
1137 schoenebeck 1411 set_file_is_shared(isSharedInstrument);
1138 persson 1261
1139     this->filename = filename ? filename : _("Unsaved Gig File");
1140     set_title(Glib::filename_display_basename(this->filename));
1141     file_has_name = filename;
1142     file_is_changed = false;
1143    
1144 schoenebeck 1225 propDialog.set_info(gig->pInfo);
1145    
1146     Gtk::MenuItem* instrument_menu =
1147     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
1148    
1149     int instrument_index = 0;
1150     Gtk::RadioMenuItem::Group instrument_group;
1151     for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;
1152     instrument = gig->GetNextInstrument()) {
1153     Gtk::TreeModel::iterator iter = m_refTreeModel->append();
1154     Gtk::TreeModel::Row row = *iter;
1155     row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1156     row[m_Columns.m_col_instr] = instrument;
1157     // create a menu item for this instrument
1158     Gtk::RadioMenuItem* item =
1159     new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());
1160     instrument_menu->get_submenu()->append(*item);
1161     item->signal_activate().connect(
1162     sigc::bind(
1163     sigc::mem_fun(*this, &MainWindow::on_instrument_selection_change),
1164     instrument_index
1165     )
1166     );
1167     instrument_index++;
1168     }
1169     instrument_menu->show();
1170     instrument_menu->get_submenu()->show_all_children();
1171    
1172     for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
1173     if (group->Name != "") {
1174     Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1175     Gtk::TreeModel::Row rowGroup = *iterGroup;
1176     rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1177     rowGroup[m_SamplesModel.m_col_group] = group;
1178     rowGroup[m_SamplesModel.m_col_sample] = NULL;
1179     for (gig::Sample* sample = group->GetFirstSample();
1180     sample; sample = group->GetNextSample()) {
1181     Gtk::TreeModel::iterator iterSample =
1182     m_refSamplesTreeModel->append(rowGroup.children());
1183     Gtk::TreeModel::Row rowSample = *iterSample;
1184     rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str();
1185     rowSample[m_SamplesModel.m_col_sample] = sample;
1186     rowSample[m_SamplesModel.m_col_group] = NULL;
1187     }
1188     }
1189     }
1190    
1191 persson 1261 file = gig;
1192    
1193 schoenebeck 1225 // select the first instrument
1194     Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1195     tree_sel_ref->select(Gtk::TreePath("0"));
1196     }
1197    
1198     void MainWindow::show_instr_props()
1199     {
1200 persson 1533 gig::Instrument* instrument = get_instrument();
1201     if (instrument)
1202 schoenebeck 1225 {
1203 persson 1533 instrumentProps.set_instrument(instrument);
1204     instrumentProps.show();
1205     instrumentProps.deiconify();
1206 schoenebeck 1225 }
1207     }
1208    
1209 schoenebeck 1415 void MainWindow::on_action_view_status_bar() {
1210     Gtk::CheckMenuItem* item =
1211     dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuView/Statusbar"));
1212     if (!item) {
1213     std::cerr << "/MenuBar/MenuView/Statusbar == NULL\n";
1214     return;
1215     }
1216     if (item->get_active()) m_StatusBar.show();
1217     else m_StatusBar.hide();
1218     }
1219    
1220 schoenebeck 1225 void MainWindow::on_button_release(GdkEventButton* button)
1221     {
1222     if (button->type == GDK_2BUTTON_PRESS) {
1223     show_instr_props();
1224     } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1225     popup_menu->popup(button->button, button->time);
1226     }
1227     }
1228    
1229     void MainWindow::on_instrument_selection_change(int index) {
1230     m_RegionChooser.set_instrument(file->GetInstrument(index));
1231     }
1232    
1233     void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {
1234     if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1235     Gtk::Menu* sample_popup =
1236     dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/SamplePopupMenu"));
1237     // update enabled/disabled state of sample popup items
1238     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1239     Gtk::TreeModel::iterator it = sel->get_selected();
1240     bool group_selected = false;
1241     bool sample_selected = false;
1242     if (it) {
1243     Gtk::TreeModel::Row row = *it;
1244     group_selected = row[m_SamplesModel.m_col_group];
1245     sample_selected = row[m_SamplesModel.m_col_sample];
1246     }
1247     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->
1248     set_sensitive(group_selected || sample_selected);
1249     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->
1250     set_sensitive(group_selected || sample_selected);
1251     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->
1252     set_sensitive(file);
1253     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->
1254     set_sensitive(group_selected || sample_selected);
1255     // show sample popup
1256     sample_popup->popup(button->button, button->time);
1257     }
1258     }
1259    
1260     void MainWindow::on_action_add_instrument() {
1261     static int __instrument_indexer = 0;
1262     if (!file) return;
1263     gig::Instrument* instrument = file->AddInstrument();
1264     __instrument_indexer++;
1265     instrument->pInfo->Name =
1266     "Unnamed Instrument " + ToString(__instrument_indexer);
1267     // update instrument tree view
1268     Gtk::TreeModel::iterator iterInstr = m_refTreeModel->append();
1269     Gtk::TreeModel::Row rowInstr = *iterInstr;
1270     rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1271     rowInstr[m_Columns.m_col_instr] = instrument;
1272 persson 1261 file_changed();
1273 schoenebeck 1225 }
1274    
1275     void MainWindow::on_action_remove_instrument() {
1276     if (!file) return;
1277 schoenebeck 1382 if (file_is_shared) {
1278     Gtk::MessageDialog msg(
1279     *this,
1280     _("You cannot delete an instrument from this file, since it's "
1281     "currently used by the sampler."),
1282     false, Gtk::MESSAGE_INFO
1283     );
1284     msg.run();
1285     return;
1286     }
1287    
1288 schoenebeck 1225 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
1289     Gtk::TreeModel::iterator it = sel->get_selected();
1290     if (it) {
1291     Gtk::TreeModel::Row row = *it;
1292     gig::Instrument* instr = row[m_Columns.m_col_instr];
1293     try {
1294     // remove instrument from the gig file
1295     if (instr) file->DeleteInstrument(instr);
1296     // remove respective row from instruments tree view
1297     m_refTreeModel->erase(it);
1298 persson 1261 file_changed();
1299 schoenebeck 1225 } catch (RIFF::Exception e) {
1300     Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1301     msg.run();
1302     }
1303     }
1304     }
1305    
1306     void MainWindow::on_action_sample_properties() {
1307     //TODO: show a dialog where the selected sample's properties can be edited
1308     Gtk::MessageDialog msg(
1309     *this, "Sorry, yet to be implemented!", false, Gtk::MESSAGE_INFO
1310     );
1311     msg.run();
1312     }
1313    
1314     void MainWindow::on_action_add_group() {
1315     static int __sample_indexer = 0;
1316     if (!file) return;
1317     gig::Group* group = file->AddGroup();
1318     group->Name = "Unnamed Group";
1319     if (__sample_indexer) group->Name += " " + ToString(__sample_indexer);
1320     __sample_indexer++;
1321     // update sample tree view
1322     Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1323     Gtk::TreeModel::Row rowGroup = *iterGroup;
1324     rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1325     rowGroup[m_SamplesModel.m_col_sample] = NULL;
1326     rowGroup[m_SamplesModel.m_col_group] = group;
1327 persson 1261 file_changed();
1328 schoenebeck 1225 }
1329    
1330     void MainWindow::on_action_add_sample() {
1331     if (!file) return;
1332     // get selected group
1333     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1334     Gtk::TreeModel::iterator it = sel->get_selected();
1335     if (!it) return;
1336     Gtk::TreeModel::Row row = *it;
1337     gig::Group* group = row[m_SamplesModel.m_col_group];
1338     if (!group) { // not a group, but a sample is selected (probably)
1339     gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1340     if (!sample) return;
1341     it = row.parent(); // resolve parent (that is the sample's group)
1342     if (!it) return;
1343     row = *it;
1344     group = row[m_SamplesModel.m_col_group];
1345     if (!group) return;
1346     }
1347     // show 'browse for file' dialog
1348     Gtk::FileChooserDialog dialog(*this, _("Add Sample(s)"));
1349     dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1350     dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1351     dialog.set_select_multiple(true);
1352     Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1353 persson 1262 const char* const supportedFileTypes[] = {
1354 schoenebeck 1225 "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1355     "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1356     "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
1357     "*.W64", "*.pvf", "*.PVF", "*.xi", "*.XI", "*.htk", "*.HTK",
1358     "*.caf", "*.CAF", NULL
1359     };
1360     for (int i = 0; supportedFileTypes[i]; i++)
1361     soundfilter.add_pattern(supportedFileTypes[i]);
1362     soundfilter.set_name("Sound Files");
1363     Gtk::FileFilter allpassfilter; // matches every file
1364     allpassfilter.add_pattern("*.*");
1365     allpassfilter.set_name("All Files");
1366     dialog.add_filter(soundfilter);
1367     dialog.add_filter(allpassfilter);
1368     if (dialog.run() == Gtk::RESPONSE_OK) {
1369     Glib::ustring error_files;
1370     Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();
1371     for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin();
1372     iter != filenames.end(); ++iter) {
1373     printf("Adding sample %s\n",(*iter).c_str());
1374     // use libsndfile to retrieve file informations
1375     SF_INFO info;
1376     info.format = 0;
1377     SNDFILE* hFile = sf_open((*iter).c_str(), SFM_READ, &info);
1378     try {
1379     if (!hFile) throw std::string("could not open file");
1380     int bitdepth;
1381     switch (info.format & 0xff) {
1382     case SF_FORMAT_PCM_S8:
1383     case SF_FORMAT_PCM_16:
1384 persson 1265 case SF_FORMAT_PCM_U8:
1385 schoenebeck 1225 bitdepth = 16;
1386     break;
1387     case SF_FORMAT_PCM_24:
1388     case SF_FORMAT_PCM_32:
1389     case SF_FORMAT_FLOAT:
1390     case SF_FORMAT_DOUBLE:
1391 persson 1265 bitdepth = 24;
1392 schoenebeck 1225 break;
1393     default:
1394     sf_close(hFile); // close sound file
1395     throw std::string("format not supported"); // unsupported subformat (yet?)
1396     }
1397     // add a new sample to the .gig file
1398     gig::Sample* sample = file->AddSample();
1399     // file name without path
1400 persson 1262 Glib::ustring filename = Glib::filename_display_basename(*iter);
1401     // remove file extension if there is one
1402     for (int i = 0; supportedFileTypes[i]; i++) {
1403     if (Glib::str_has_suffix(filename, supportedFileTypes[i] + 1)) {
1404     filename.erase(filename.length() - strlen(supportedFileTypes[i] + 1));
1405     break;
1406     }
1407     }
1408     sample->pInfo->Name = filename;
1409 schoenebeck 1225 sample->Channels = info.channels;
1410     sample->BitDepth = bitdepth;
1411     sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1412     sample->SamplesPerSecond = info.samplerate;
1413 persson 1265 sample->AverageBytesPerSecond = sample->FrameSize * sample->SamplesPerSecond;
1414     sample->BlockAlign = sample->FrameSize;
1415     sample->SamplesTotal = info.frames;
1416    
1417     SF_INSTRUMENT instrument;
1418     if (sf_command(hFile, SFC_GET_INSTRUMENT,
1419     &instrument, sizeof(instrument)) != SF_FALSE)
1420     {
1421     sample->MIDIUnityNote = instrument.basenote;
1422    
1423 persson 1303 #if HAVE_SF_INSTRUMENT_LOOPS
1424 persson 1265 if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
1425     sample->Loops = 1;
1426    
1427     switch (instrument.loops[0].mode) {
1428     case SF_LOOP_FORWARD:
1429     sample->LoopType = gig::loop_type_normal;
1430     break;
1431     case SF_LOOP_BACKWARD:
1432     sample->LoopType = gig::loop_type_backward;
1433     break;
1434     case SF_LOOP_ALTERNATING:
1435     sample->LoopType = gig::loop_type_bidirectional;
1436     break;
1437     }
1438     sample->LoopStart = instrument.loops[0].start;
1439     sample->LoopEnd = instrument.loops[0].end;
1440     sample->LoopPlayCount = instrument.loops[0].count;
1441     sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
1442     }
1443 persson 1303 #endif
1444 persson 1265 }
1445    
1446 schoenebeck 1225 // schedule resizing the sample (which will be done
1447     // physically when File::Save() is called)
1448     sample->Resize(info.frames);
1449     // make sure sample is part of the selected group
1450     group->AddSample(sample);
1451     // schedule that physical resize and sample import
1452     // (data copying), performed when "Save" is requested
1453     SampleImportItem sched_item;
1454     sched_item.gig_sample = sample;
1455     sched_item.sample_path = *iter;
1456     m_SampleImportQueue.push_back(sched_item);
1457     // add sample to the tree view
1458     Gtk::TreeModel::iterator iterSample =
1459     m_refSamplesTreeModel->append(row.children());
1460     Gtk::TreeModel::Row rowSample = *iterSample;
1461 persson 1262 rowSample[m_SamplesModel.m_col_name] = filename;
1462 schoenebeck 1225 rowSample[m_SamplesModel.m_col_sample] = sample;
1463     rowSample[m_SamplesModel.m_col_group] = NULL;
1464     // close sound file
1465     sf_close(hFile);
1466 persson 1261 file_changed();
1467 schoenebeck 1225 } catch (std::string what) { // remember the files that made trouble (and their cause)
1468     if (error_files.size()) error_files += "\n";
1469     error_files += *iter += " (" + what + ")";
1470     }
1471     }
1472     // show error message box when some file(s) could not be opened / added
1473     if (error_files.size()) {
1474 schoenebeck 1382 Glib::ustring txt = _("Could not add the following sample(s):\n") + error_files;
1475 schoenebeck 1225 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1476     msg.run();
1477     }
1478     }
1479     }
1480    
1481     void MainWindow::on_action_remove_sample() {
1482     if (!file) return;
1483     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1484     Gtk::TreeModel::iterator it = sel->get_selected();
1485     if (it) {
1486     Gtk::TreeModel::Row row = *it;
1487     gig::Group* group = row[m_SamplesModel.m_col_group];
1488     gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1489     Glib::ustring name = row[m_SamplesModel.m_col_name];
1490     try {
1491     // remove group or sample from the gig file
1492     if (group) {
1493     // temporarily remember the samples that bolong to
1494     // that group (we need that to clean the queue)
1495     std::list<gig::Sample*> members;
1496     for (gig::Sample* pSample = group->GetFirstSample();
1497     pSample; pSample = group->GetNextSample()) {
1498     members.push_back(pSample);
1499     }
1500 schoenebeck 1322 // notify everybody that we're going to remove these samples
1501     samples_to_be_removed_signal.emit(members);
1502 schoenebeck 1225 // delete the group in the .gig file including the
1503     // samples that belong to the group
1504     file->DeleteGroup(group);
1505 schoenebeck 1322 // notify that we're done with removal
1506     samples_removed_signal.emit();
1507 schoenebeck 1225 // if sample(s) were just previously added, remove
1508     // them from the import queue
1509     for (std::list<gig::Sample*>::iterator member = members.begin();
1510     member != members.end(); ++member) {
1511     for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1512     iter != m_SampleImportQueue.end(); ++iter) {
1513     if ((*iter).gig_sample == *member) {
1514     printf("Removing previously added sample '%s' from group '%s'\n",
1515     (*iter).sample_path.c_str(), name.c_str());
1516     m_SampleImportQueue.erase(iter);
1517     break;
1518     }
1519     }
1520     }
1521 persson 1261 file_changed();
1522 schoenebeck 1225 } else if (sample) {
1523 schoenebeck 1322 // notify everybody that we're going to remove this sample
1524     std::list<gig::Sample*> lsamples;
1525     lsamples.push_back(sample);
1526     samples_to_be_removed_signal.emit(lsamples);
1527 schoenebeck 1225 // remove sample from the .gig file
1528     file->DeleteSample(sample);
1529 schoenebeck 1322 // notify that we're done with removal
1530     samples_removed_signal.emit();
1531 schoenebeck 1225 // if sample was just previously added, remove it from
1532     // the import queue
1533     for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1534     iter != m_SampleImportQueue.end(); ++iter) {
1535     if ((*iter).gig_sample == sample) {
1536     printf("Removing previously added sample '%s'\n",
1537     (*iter).sample_path.c_str());
1538     m_SampleImportQueue.erase(iter);
1539     break;
1540     }
1541     }
1542 persson 1303 dimreg_changed();
1543 persson 1261 file_changed();
1544 schoenebeck 1225 }
1545     // remove respective row(s) from samples tree view
1546     m_refSamplesTreeModel->erase(it);
1547     } catch (RIFF::Exception e) {
1548 schoenebeck 1322 // pretend we're done with removal (i.e. to avoid dead locks)
1549     samples_removed_signal.emit();
1550     // show error message
1551 schoenebeck 1225 Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1552     msg.run();
1553     }
1554     }
1555     }
1556    
1557 persson 1303 // For some reason drag_data_get gets called two times for each
1558     // drag'n'drop (at least when target is an Entry). This work-around
1559     // makes sure the code in drag_data_get and drop_drag_data_received is
1560     // only executed once, as drag_begin only gets called once.
1561     void MainWindow::on_sample_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
1562     {
1563     first_call_to_drag_data_get = true;
1564     }
1565    
1566 schoenebeck 1225 void MainWindow::on_sample_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,
1567     Gtk::SelectionData& selection_data, guint, guint)
1568     {
1569 persson 1303 if (!first_call_to_drag_data_get) return;
1570     first_call_to_drag_data_get = false;
1571    
1572 schoenebeck 1225 // get selected sample
1573     gig::Sample* sample = NULL;
1574     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1575     Gtk::TreeModel::iterator it = sel->get_selected();
1576     if (it) {
1577     Gtk::TreeModel::Row row = *it;
1578     sample = row[m_SamplesModel.m_col_sample];
1579     }
1580     // pass the gig::Sample as pointer
1581     selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&sample,
1582     sizeof(sample)/*length of data in bytes*/);
1583     }
1584    
1585     void MainWindow::on_sample_label_drop_drag_data_received(
1586     const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1587     const Gtk::SelectionData& selection_data, guint, guint time)
1588     {
1589     gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1590    
1591 persson 1265 if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
1592 persson 1303 std::cout << "Drop received sample \"" <<
1593     sample->pInfo->Name << "\"" << std::endl;
1594     // drop success
1595     context->drop_reply(true, time);
1596    
1597 schoenebeck 1322 //TODO: we should better move most of the following code to DimRegionEdit::set_sample()
1598    
1599     // notify everybody that we're going to alter the region
1600     gig::Region* region = m_RegionChooser.get_region();
1601     region_to_be_changed_signal.emit(region);
1602    
1603 persson 1303 // find the samplechannel dimension
1604     gig::dimension_def_t* stereo_dimension = 0;
1605     for (int i = 0 ; i < region->Dimensions ; i++) {
1606     if (region->pDimensionDefinitions[i].dimension ==
1607     gig::dimension_samplechannel) {
1608     stereo_dimension = &region->pDimensionDefinitions[i];
1609     break;
1610     }
1611 schoenebeck 1225 }
1612 persson 1303 bool channels_changed = false;
1613     if (sample->Channels == 1 && stereo_dimension) {
1614     // remove the samplechannel dimension
1615     region->DeleteDimension(stereo_dimension);
1616     channels_changed = true;
1617     region_changed();
1618     }
1619     dimreg_edit.set_sample(sample);
1620    
1621     if (sample->Channels == 2 && !stereo_dimension) {
1622     // add samplechannel dimension
1623     gig::dimension_def_t dim;
1624     dim.dimension = gig::dimension_samplechannel;
1625     dim.bits = 1;
1626     dim.zones = 2;
1627     region->AddDimension(&dim);
1628     channels_changed = true;
1629     region_changed();
1630     }
1631     if (channels_changed) {
1632     // unmap all samples with wrong number of channels
1633     // TODO: maybe there should be a warning dialog for this
1634     for (int i = 0 ; i < region->DimensionRegions ; i++) {
1635     gig::DimensionRegion* d = region->pDimensionRegions[i];
1636     if (d->pSample && d->pSample->Channels != sample->Channels) {
1637 schoenebeck 1322 gig::Sample* oldref = d->pSample;
1638     d->pSample = NULL;
1639     sample_ref_changed_signal.emit(oldref, NULL);
1640 persson 1303 }
1641     }
1642     }
1643    
1644 schoenebeck 1322 // notify we're done with altering
1645     region_changed_signal.emit(region);
1646    
1647 persson 1460 file_changed();
1648    
1649 persson 1303 return;
1650 schoenebeck 1225 }
1651     // drop failed
1652     context->drop_reply(false, time);
1653     }
1654    
1655     void MainWindow::sample_name_changed(const Gtk::TreeModel::Path& path,
1656     const Gtk::TreeModel::iterator& iter) {
1657     if (!iter) return;
1658     Gtk::TreeModel::Row row = *iter;
1659     Glib::ustring name = row[m_SamplesModel.m_col_name];
1660     gig::Group* group = row[m_SamplesModel.m_col_group];
1661     gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1662     if (group) {
1663 persson 1261 if (group->Name != name) {
1664     group->Name = name;
1665     printf("group name changed\n");
1666     file_changed();
1667     }
1668 schoenebeck 1225 } else if (sample) {
1669 persson 1261 if (sample->pInfo->Name != name.raw()) {
1670     sample->pInfo->Name = name.raw();
1671     printf("sample name changed\n");
1672     file_changed();
1673     }
1674 schoenebeck 1225 }
1675     }
1676    
1677     void MainWindow::instrument_name_changed(const Gtk::TreeModel::Path& path,
1678     const Gtk::TreeModel::iterator& iter) {
1679     if (!iter) return;
1680     Gtk::TreeModel::Row row = *iter;
1681     Glib::ustring name = row[m_Columns.m_col_name];
1682     gig::Instrument* instrument = row[m_Columns.m_col_instr];
1683 persson 1261 if (instrument && instrument->pInfo->Name != name.raw()) {
1684     instrument->pInfo->Name = name.raw();
1685     file_changed();
1686     }
1687 schoenebeck 1225 }
1688 schoenebeck 1322
1689 schoenebeck 1411 void MainWindow::set_file_is_shared(bool b) {
1690     this->file_is_shared = b;
1691    
1692     if (file_is_shared) {
1693     m_AttachedStateLabel.set_label(_("live-mode"));
1694     m_AttachedStateImage.set(
1695     Gdk::Pixbuf::create_from_xpm_data(status_attached_xpm)
1696     );
1697     } else {
1698     m_AttachedStateLabel.set_label(_("stand-alone"));
1699     m_AttachedStateImage.set(
1700     Gdk::Pixbuf::create_from_xpm_data(status_detached_xpm)
1701     );
1702     }
1703     }
1704    
1705 schoenebeck 1339 sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {
1706 schoenebeck 1322 return file_structure_to_be_changed_signal;
1707     }
1708    
1709 schoenebeck 1339 sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_changed() {
1710 schoenebeck 1322 return file_structure_changed_signal;
1711     }
1712    
1713 schoenebeck 1339 sigc::signal<void, std::list<gig::Sample*> >& MainWindow::signal_samples_to_be_removed() {
1714 schoenebeck 1322 return samples_to_be_removed_signal;
1715     }
1716    
1717 schoenebeck 1339 sigc::signal<void>& MainWindow::signal_samples_removed() {
1718 schoenebeck 1322 return samples_removed_signal;
1719     }
1720    
1721 schoenebeck 1339 sigc::signal<void, gig::Region*>& MainWindow::signal_region_to_be_changed() {
1722 schoenebeck 1322 return region_to_be_changed_signal;
1723     }
1724    
1725 schoenebeck 1339 sigc::signal<void, gig::Region*>& MainWindow::signal_region_changed() {
1726 schoenebeck 1322 return region_changed_signal;
1727     }
1728    
1729 schoenebeck 1339 sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& MainWindow::signal_sample_ref_changed() {
1730 schoenebeck 1322 return sample_ref_changed_signal;
1731     }
1732    
1733 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_to_be_changed() {
1734 schoenebeck 1322 return dimreg_to_be_changed_signal;
1735     }
1736    
1737 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_changed() {
1738 schoenebeck 1322 return dimreg_changed_signal;
1739     }

  ViewVC Help
Powered by ViewVC