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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1225 by schoenebeck, Sun Jun 10 10:56:11 2007 UTC revision 1582 by persson, Sat Dec 8 12:28:53 2007 UTC
# Line 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
 #include <libintl.h>  
20  #include <iostream>  #include <iostream>
21    
22  #include <gtkmm/filechooserdialog.h>  #include <gtkmm/filechooserdialog.h>
# Line 25  Line 24 
24  #include <gtkmm/stock.h>  #include <gtkmm/stock.h>
25  #include <gtkmm/targetentry.h>  #include <gtkmm/targetentry.h>
26  #include <gtkmm/main.h>  #include <gtkmm/main.h>
27    #include <gtkmm/toggleaction.h>
28    
29  #if GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6  #include "global.h"
30    
31    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
32  #define ABOUT_DIALOG  #define ABOUT_DIALOG
33  #include <gtkmm/aboutdialog.h>  #include <gtkmm/aboutdialog.h>
34  #endif  #endif
35    
36    #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  #include <stdio.h>  #include <stdio.h>
49  #include <sndfile.h>  #include <sndfile.h>
50    
51  #include "mainwindow.h"  #include "mainwindow.h"
52    
53  #define _(String) gettext(String)  #include "../../gfx/status_attached.xpm"
54    #include "../../gfx/status_detached.xpm"
55    
56  template<class T> inline std::string ToString(T o) {  template<class T> inline std::string ToString(T o) {
57      std::stringstream ss;      std::stringstream ss;
# Line 44  template<class T> inline std::string ToS Line 59  template<class T> inline std::string ToS
59      return ss.str();      return ss.str();
60  }  }
61    
62  MainWindow::MainWindow()  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    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  {  {
93  //    set_border_width(5);  //    set_border_width(5);
94  //    set_default_size(400, 200);  //    set_default_size(400, 200);
# Line 74  MainWindow::MainWindow() Line 118  MainWindow::MainWindow()
118      m_TreeViewNotebook.set_size_request(300);      m_TreeViewNotebook.set_size_request(300);
119    
120      m_HPaned.add1(m_TreeViewNotebook);      m_HPaned.add1(m_TreeViewNotebook);
121      m_HPaned.add2(dimreg_edit);      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        dimreg_vbox.pack_start(dimreg_hbox, Gtk::PACK_SHRINK);
128        m_HPaned.add2(dimreg_vbox);
129    
130    
131      m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");      m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");
# Line 99  MainWindow::MainWindow() Line 150  MainWindow::MainWindow()
150      action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS);      action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS);
151      action->property_label() = action->property_label() + "...";      action->property_label() = action->property_label() + "...";
152      actionGroup->add(action,      actionGroup->add(action,
153                       *(new Gtk::AccelKey("<shift><control>s")),                       Gtk::AccelKey("<shift><control>s"),
154                       sigc::mem_fun(                       sigc::mem_fun(
155                           *this, &MainWindow::on_action_file_save_as)                           *this, &MainWindow::on_action_file_save_as));
         );  
156      actionGroup->add(Gtk::Action::create("Properties",      actionGroup->add(Gtk::Action::create("Properties",
157                                           Gtk::Stock::PROPERTIES),                                           Gtk::Stock::PROPERTIES),
158                       sigc::mem_fun(                       sigc::mem_fun(
# Line 113  MainWindow::MainWindow() Line 163  MainWindow::MainWindow()
163                           *this, &MainWindow::show_instr_props));                           *this, &MainWindow::show_instr_props));
164      actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),      actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),
165                       sigc::mem_fun(                       sigc::mem_fun(
166                           *this, &MainWindow::hide));                           *this, &MainWindow::on_action_quit));
167      actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));      actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));
168    
169        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      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);
178      actionGroup->add(Gtk::Action::create("MenuHelp",      actionGroup->add(Gtk::Action::create("MenuHelp",
179                                           action->property_label()));                                           action->property_label()));
# Line 153  MainWindow::MainWindow() Line 211  MainWindow::MainWindow()
211    
212      uiManager = Gtk::UIManager::create();      uiManager = Gtk::UIManager::create();
213      uiManager->insert_action_group(actionGroup);      uiManager->insert_action_group(actionGroup);
214      // add_accel_group(uiManager->get_accel_group());      add_accel_group(uiManager->get_accel_group());
215    
216      Glib::ustring ui_info =      Glib::ustring ui_info =
217          "<ui>"          "<ui>"
# Line 171  MainWindow::MainWindow() Line 229  MainWindow::MainWindow()
229          "    </menu>"          "    </menu>"
230          "    <menu action='MenuInstrument'>"          "    <menu action='MenuInstrument'>"
231          "    </menu>"          "    </menu>"
232            "    <menu action='MenuView'>"
233            "      <menuitem action='Statusbar'/>"
234            "    </menu>"
235  #ifdef ABOUT_DIALOG  #ifdef ABOUT_DIALOG
236          "    <menu action='MenuHelp'>"          "    <menu action='MenuHelp'>"
237          "      <menuitem action='About'/>"          "      <menuitem action='About'/>"
# Line 200  MainWindow::MainWindow() Line 261  MainWindow::MainWindow()
261      m_VBox.pack_start(m_HPaned);      m_VBox.pack_start(m_HPaned);
262      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
263      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
264        m_VBox.pack_start(m_StatusBar, Gtk::PACK_SHRINK);
265    
266      m_RegionChooser.signal_sel_changed().connect(      // 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        m_RegionChooser.signal_region_selected().connect(
272          sigc::mem_fun(*this, &MainWindow::region_changed) );          sigc::mem_fun(*this, &MainWindow::region_changed) );
273      m_DimRegionChooser.signal_sel_changed().connect(      m_DimRegionChooser.signal_dimregion_selected().connect(
274          sigc::mem_fun(*this, &MainWindow::dimreg_changed) );          sigc::mem_fun(*this, &MainWindow::dimreg_changed) );
275    
276    
# Line 235  MainWindow::MainWindow() Line 302  MainWindow::MainWindow()
302      std::list<Gtk::TargetEntry> drag_target_gig_sample;      std::list<Gtk::TargetEntry> drag_target_gig_sample;
303      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
304      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
305        m_TreeViewSamples.signal_drag_begin().connect(
306            sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)
307        );
308      m_TreeViewSamples.signal_drag_data_get().connect(      m_TreeViewSamples.signal_drag_data_get().connect(
309          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
310      );      );
# Line 242  MainWindow::MainWindow() Line 312  MainWindow::MainWindow()
312      dimreg_edit.wSample->signal_drag_data_received().connect(      dimreg_edit.wSample->signal_drag_data_received().connect(
313          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
314      );      );
315        dimreg_edit.signal_dimreg_changed().connect(
316            sigc::hide(sigc::mem_fun(*this, &MainWindow::file_changed)));
317        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        propDialog.signal_info_changed().connect(
324            sigc::mem_fun(*this, &MainWindow::file_changed));
325    
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        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      file = 0;      file = 0;
362        file_is_changed = false;
363        set_file_is_shared(false);
364    
365      show_all_children();      show_all_children();
366    
367        // start with a new gig file by default
368        on_action_file_new();
369  }  }
370    
371  MainWindow::~MainWindow()  MainWindow::~MainWindow()
372  {  {
373  }  }
374    
375  void MainWindow::region_changed()  bool MainWindow::on_delete_event(GdkEventAny* event)
376  {  {
377      m_DimRegionChooser.set_region(m_RegionChooser.get_region());      return !file_is_shared && file_is_changed && !close_confirmation_dialog();
378  }  }
379    
380  void MainWindow::dimreg_changed()  void MainWindow::on_action_quit()
381  {  {
382      dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
383        hide();
384  }  }
385    
386  void MainWindow::on_sel_change()  void MainWindow::region_changed()
387    {
388        m_DimRegionChooser.set_region(m_RegionChooser.get_region());
389    }
390    
391    gig::Instrument* MainWindow::get_instrument()
392  {  {
393        gig::Instrument* instrument = 0;
394      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
395    
396      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
397      if (it) {      if (it) {
398          Gtk::TreeModel::Row row = *it;          Gtk::TreeModel::Row row = *it;
399          std::cout << row[m_Columns.m_col_name] << std::endl;          instrument = row[m_Columns.m_col_instr];
400        }
401        return instrument;
402    }
403    
404          m_RegionChooser.set_instrument(row[m_Columns.m_col_instr]);  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      } else {      } else {
413          m_RegionChooser.set_instrument(0);          m_DimRegionChooser.get_dimregions(region, stereo, dimreg_edit.dimregs);
414      }      }
415  }  }
416    
417    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  void loader_progress_callback(gig::progress_t* progress)  void loader_progress_callback(gig::progress_t* progress)
459  {  {
460      Loader* loader = static_cast<Loader*>(progress->custom);      Loader* loader = static_cast<Loader*>(progress->custom);
# Line 362  void MainWindow::__clear() { Line 540  void MainWindow::__clear() {
540      m_refTreeModel->clear();      m_refTreeModel->clear();
541      m_refSamplesTreeModel->clear();      m_refSamplesTreeModel->clear();
542      // free libgig's gig::File instance      // free libgig's gig::File instance
543      if (file) {      if (file && !file_is_shared) delete file;
544          delete file;      file = NULL;
545          file = NULL;      set_file_is_shared(false);
     }  
546  }  }
547    
548  void MainWindow::on_action_file_new()  void MainWindow::on_action_file_new()
549  {  {
550        if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
551    
552        if (file_is_shared && !leaving_shared_mode_dialog()) return;
553    
554      // clear all GUI elements      // clear all GUI elements
555      __clear();      __clear();
556      // create a new .gig file (virtually yet)      // create a new .gig file (virtually yet)
# Line 378  void MainWindow::on_action_file_new() Line 559  void MainWindow::on_action_file_new()
559      gig::Instrument* pInstrument = pFile->AddInstrument();      gig::Instrument* pInstrument = pFile->AddInstrument();
560      pInstrument->pInfo->Name = "Unnamed Instrument";      pInstrument->pInfo->Name = "Unnamed Instrument";
561      // update GUI with that new gig::File      // update GUI with that new gig::File
562      load_gig(pFile, NULL /*no file name yet*/);      load_gig(pFile, 0 /*no file name yet*/);
563    }
564    
565    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    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
572        dialog.set_secondary_text(_("If you close without saving, your changes will be lost."));
573    #endif
574        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        dialog.hide();
580        if (response == Gtk::RESPONSE_YES) return file_save();
581        return response != Gtk::RESPONSE_CANCEL;
582    }
583    
584    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  void MainWindow::on_action_file_open()  void MainWindow::on_action_file_open()
603  {  {
604        if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
605    
606        if (file_is_shared && !leaving_shared_mode_dialog()) return;
607    
608      Gtk::FileChooserDialog dialog(*this, _("Open file"));      Gtk::FileChooserDialog dialog(*this, _("Open file"));
609      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
610      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
611        dialog.set_default_response(Gtk::RESPONSE_OK);
612      Gtk::FileFilter filter;      Gtk::FileFilter filter;
613      filter.add_pattern("*.gig");      filter.add_pattern("*.gig");
614      dialog.set_filter(filter);      dialog.set_filter(filter);
615        if (current_dir != "") {
616            dialog.set_current_folder(current_dir);
617        }
618      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
619          printf("filename=%s\n", dialog.get_filename().c_str());          std::string filename = dialog.get_filename();
620          __clear();          printf("filename=%s\n", filename.c_str());
621          printf("on_action_file_open self=%x\n", Glib::Thread::self());          printf("on_action_file_open self=%x\n", Glib::Thread::self());
622          load_file(dialog.get_filename().c_str());          load_file(filename.c_str());
623            current_dir = Glib::path_get_dirname(filename);
624      }      }
625  }  }
626    
627  void MainWindow::load_file(const char* name)  void MainWindow::load_file(const char* name)
628  {  {
629        __clear();
630      load_dialog = new LoadDialog("Loading...", *this);      load_dialog = new LoadDialog("Loading...", *this);
631      load_dialog->show_all();      load_dialog->show_all();
632      loader = new Loader(strdup(name));      loader = new Loader(strdup(name));
# Line 416  void MainWindow::load_instrument(gig::In Line 644  void MainWindow::load_instrument(gig::In
644          msg.run();          msg.run();
645          Gtk::Main::quit();          Gtk::Main::quit();
646      }      }
647        // clear all GUI elements
648        __clear();
649        // load the instrument
650      gig::File* pFile = (gig::File*) instr->GetParent();      gig::File* pFile = (gig::File*) instr->GetParent();
651      load_gig(pFile, NULL /*file name*/);      load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);
652      //TODO: automatically select the given instrument      //TODO: automatically select the given instrument
653  }  }
654    
# Line 436  void MainWindow::on_loader_finished() Line 667  void MainWindow::on_loader_finished()
667    
668  void MainWindow::on_action_file_save()  void MainWindow::on_action_file_save()
669  {  {
670      if (!file) return;      file_save();
671    }
672    
673    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    bool MainWindow::file_save()
698    {
699        if (!check_if_savable()) return false;
700        if (!file_is_shared && !file_has_name) return file_save_as();
701    
702      std::cout << "Saving file\n" << std::flush;      std::cout << "Saving file\n" << std::flush;
703        file_structure_to_be_changed_signal.emit(this->file);
704      try {      try {
705          file->Save();          file->Save();
706            if (file_is_changed) {
707                set_title(get_title().substr(1));
708                file_is_changed = false;
709            }
710      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
711          Glib::ustring txt = "Could not save file: " + e.Message;          file_structure_changed_signal.emit(this->file);
712            Glib::ustring txt = _("Could not save file: ") + e.Message;
713          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
714          msg.run();          msg.run();
715          return;          return false;
716      }      }
717      std::cout << "Saving file done\n" << std::flush;      std::cout << "Saving file done\n" << std::flush;
718      __import_queued_samples();      __import_queued_samples();
719        file_structure_changed_signal.emit(this->file);
720        return true;
721  }  }
722    
723  void MainWindow::on_action_file_save_as()  void MainWindow::on_action_file_save_as()
724  {  {
725      if (!file) return;      if (!check_if_savable()) return;
726      Gtk::FileChooserDialog dialog(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SAVE);      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      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
733      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
734        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      Gtk::FileFilter filter;      Gtk::FileFilter filter;
741      filter.add_pattern("*.gig");      filter.add_pattern("*.gig");
742      dialog.set_filter(filter);      dialog.set_filter(filter);
743    
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      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
752          printf("filename=%s\n", dialog.get_filename().c_str());          file_structure_to_be_changed_signal.emit(this->file);
753          try {          try {
754              file->Save(dialog.get_filename());              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          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
766              Glib::ustring txt = "Could not save file: " + e.Message;              file_structure_changed_signal.emit(this->file);
767                Glib::ustring txt = _("Could not save file: ") + e.Message;
768              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
769              msg.run();              msg.run();
770              return;              return false;
771          }          }
772          __import_queued_samples();          __import_queued_samples();
773            file_structure_changed_signal.emit(this->file);
774            return true;
775      }      }
776        return false;
777  }  }
778    
779  // actually write the sample(s)' data to the gig file  // actually write the sample(s)' data to the gig file
# Line 490  void MainWindow::__import_queued_samples Line 793  void MainWindow::__import_queued_samples
793              int bitdepth;              int bitdepth;
794              switch (info.format & 0xff) {              switch (info.format & 0xff) {
795                  case SF_FORMAT_PCM_S8:                  case SF_FORMAT_PCM_S8:
                     bitdepth = 16; // we simply convert to 16 bit for now  
                     break;  
796                  case SF_FORMAT_PCM_16:                  case SF_FORMAT_PCM_16:
797                    case SF_FORMAT_PCM_U8:
798                      bitdepth = 16;                      bitdepth = 16;
799                      break;                      break;
800                  case SF_FORMAT_PCM_24:                  case SF_FORMAT_PCM_24:
                     bitdepth = 32; // we simply convert to 32 bit for now  
                     break;  
801                  case SF_FORMAT_PCM_32:                  case SF_FORMAT_PCM_32:
                     bitdepth = 32;  
                     break;  
                 case SF_FORMAT_PCM_U8:  
                     bitdepth = 16; // we simply convert to 16 bit for now  
                     break;  
802                  case SF_FORMAT_FLOAT:                  case SF_FORMAT_FLOAT:
                     bitdepth = 32;  
                     break;  
803                  case SF_FORMAT_DOUBLE:                  case SF_FORMAT_DOUBLE:
804                      bitdepth = 32; // I guess we will always truncate this to 32 bit                      bitdepth = 24;
805                      break;                      break;
806                  default:                  default:
807                      sf_close(hFile); // close sound file                      sf_close(hFile); // close sound file
808                      throw std::string("format not supported"); // unsupported subformat (yet?)                      throw std::string("format not supported"); // unsupported subformat (yet?)
809              }              }
810              // allocate appropriate copy buffer (TODO: for now we copy  
811              // it in one piece, might be tough for very long samples)              const int bufsize = 10000;
             // and copy sample data into buffer  
             int8_t* buffer = NULL;  
812              switch (bitdepth) {              switch (bitdepth) {
813                  case 16:                  case 16: {
814                      buffer = new int8_t[2 * info.channels * info.frames];                      short* buffer = new short[bufsize * info.channels];
815                      // libsndfile does the conversion for us (if needed)                      sf_count_t cnt = info.frames;
816                      sf_readf_short(hFile, (short*) buffer, info.frames);                      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                      break;                      break;
825                  case 32:                  }
826                      buffer = new int8_t[4 * info.channels * info.frames];                  case 24: {
827                      // libsndfile does the conversion for us (if needed)                      int* srcbuf = new int[bufsize * info.channels];
828                      sf_readf_int(hFile, (int*) buffer, info.frames);                      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                      break;                      break;
846                    }
847              }              }
             // write from buffer directly (physically) into .gig file  
             (*iter).gig_sample->Write(buffer, info.frames);  
848              // cleanup              // cleanup
849              sf_close(hFile);              sf_close(hFile);
             delete[] buffer;  
850              // on success we remove the sample from the import queue,              // on success we remove the sample from the import queue,
851              // otherwise keep it, maybe it works the next time ?              // otherwise keep it, maybe it works the next time ?
852              std::list<SampleImportItem>::iterator cur = iter;              std::list<SampleImportItem>::iterator cur = iter;
# Line 549  void MainWindow::__import_queued_samples Line 861  void MainWindow::__import_queued_samples
861      }      }
862      // show error message box when some sample(s) could not be imported      // show error message box when some sample(s) could not be imported
863      if (error_files.size()) {      if (error_files.size()) {
864          Glib::ustring txt = "Could not import the following sample(s):\n" + error_files;          Glib::ustring txt = _("Could not import the following sample(s):\n") + error_files;
865          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
866          msg.run();          msg.run();
867      }      }
# Line 566  void MainWindow::on_action_help_about() Line 878  void MainWindow::on_action_help_about()
878  #ifdef ABOUT_DIALOG  #ifdef ABOUT_DIALOG
879      Gtk::AboutDialog dialog;      Gtk::AboutDialog dialog;
880      dialog.set_version(VERSION);      dialog.set_version(VERSION);
881        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      dialog.run();      dialog.run();
894  #endif  #endif
895  }  }
896    
897  PropDialog::PropDialog()  PropDialog::PropDialog()
898      : table(2,1)      : 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  {  {
918        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      table.set_col_spacings(5);      table.set_col_spacings(5);
956      const char* propLabels[] = {      add(vbox);
957          "Name:",      table.set_border_width(5);
958          "CreationDate:",      vbox.add(table);
959          "Comments:", // TODO: multiline      vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
960          "Product:",      buttonBox.set_layout(Gtk::BUTTONBOX_END);
961          "Copyright:",      buttonBox.set_border_width(5);
962          "Artists:",      buttonBox.show();
963          "Genre:",      buttonBox.pack_start(quitButton);
964          "Keywords:",      quitButton.set_flags(Gtk::CAN_DEFAULT);
965          "Engineer:",      quitButton.grab_focus();
966          "Technician:",      quitButton.signal_clicked().connect(
967          "Software:", // TODO: readonly          sigc::mem_fun(*this, &PropDialog::hide));
         "Medium:",  
         "Source:",  
         "SourceForm:",  
         "Commissioned:",  
         "Subject:"  
     };  
     for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {  
         label[i].set_text(propLabels[i]);  
         label[i].set_alignment(Gtk::ALIGN_LEFT);  
         table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);  
         table.attach(entry[i], 1, 2, i, i + 1, Gtk::FILL | Gtk::EXPAND,  
                      Gtk::SHRINK);  
     }  
968    
969      add(table);      quitButton.show();
970      // add_button(Gtk::Stock::CANCEL, 0);      vbox.show();
     // add_button(Gtk::Stock::OK, 1);  
971      show_all_children();      show_all_children();
972  }  }
973    
974  void PropDialog::set_info(DLS::Info* info)  void PropDialog::set_info(DLS::Info* info)
975  {  {
976      entry[0].set_text(info->Name);      this->info = info;
977      entry[1].set_text(info->CreationDate);      update_model++;
978      entry[2].set_text(Glib::convert(info->Comments, "UTF-8", "ISO-8859-1"));      eName.set_value(info->Name);
979      entry[3].set_text(info->Product);      eCreationDate.set_value(info->CreationDate);
980      entry[4].set_text(info->Copyright);      eComments.set_value(info->Comments);
981      entry[5].set_text(info->Artists);      eProduct.set_value(info->Product);
982      entry[6].set_text(info->Genre);      eCopyright.set_value(info->Copyright);
983      entry[7].set_text(info->Keywords);      eArtists.set_value(info->Artists);
984      entry[8].set_text(info->Engineer);      eGenre.set_value(info->Genre);
985      entry[9].set_text(info->Technician);      eKeywords.set_value(info->Keywords);
986      entry[10].set_text(info->Software);      eEngineer.set_value(info->Engineer);
987      entry[11].set_text(info->Medium);      eTechnician.set_value(info->Technician);
988      entry[12].set_text(info->Source);      eSoftware.set_value(info->Software);
989      entry[13].set_text(info->SourceForm);      eMedium.set_value(info->Medium);
990      entry[14].set_text(info->Commissioned);      eSource.set_value(info->Source);
991      entry[15].set_text(info->Subject);      eSourceForm.set_value(info->SourceForm);
992  }      eCommissioned.set_value(info->Commissioned);
993        eSubject.set_value(info->Subject);
994  void InstrumentProps::add_prop(LabelWidget& prop)      update_model--;
995  {  }
996      table.attach(prop.label, 0, 1, rowno, rowno + 1,  
997                   Gtk::FILL, Gtk::SHRINK);  sigc::signal<void>& PropDialog::signal_info_changed()
998      table.attach(prop.widget, 1, 2, rowno, rowno + 1,  {
999                   Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);      return info_changed;
1000      rowno++;  }
1001    
1002    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  InstrumentProps::InstrumentProps()  InstrumentProps::InstrumentProps()
1034      : table(2,1),      : table(2,1),
1035        quitButton(Gtk::Stock::CLOSE),        quitButton(Gtk::Stock::CLOSE),
1036        eName("Name"),        eName("Name"),
1037        eIsDrum("IsDrum"),        eIsDrum("Is drum"),
1038        eMIDIBank("MIDIBank", 0, 16383),        eMIDIBank("MIDI bank", 0, 16383),
1039        eMIDIProgram("MIDIProgram"),        eMIDIProgram("MIDI program"),
1040        eAttenuation("Attenuation", 0, 96, 0, 1),        eAttenuation("Attenuation", 0, 96, 0, 1),
1041        eGainPlus6("Gain +6dB", eAttenuation, -6),        eGainPlus6("Gain +6dB", eAttenuation, -6),
1042        eEffectSend("EffectSend", 0, 65535),        eEffectSend("Effect send", 0, 65535),
1043        eFineTune("FineTune", -8400, 8400),        eFineTune("Fine tune", -8400, 8400),
1044        ePitchbendRange("PitchbendRange", 0, 12),        ePitchbendRange("Pitchbend range", 0, 12),
1045        ePianoReleaseMode("PianoReleaseMode"),        ePianoReleaseMode("Piano release mode"),
1046        eDimensionKeyRangeLow("DimensionKeyRangeLow"),        eDimensionKeyRangeLow("Dimension key range low"),
1047        eDimensionKeyRangeHigh("DimensionKeyRangeHigh")        eDimensionKeyRangeHigh("Dimension key range high"),
1048  {        update_model(0)
1049      set_title("Instrument properties");  {
1050        set_title("Instrument Properties");
1051    
1052        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    
     rowno = 0;  
1066      table.set_col_spacings(5);      table.set_col_spacings(5);
1067    
1068      add_prop(eName);      table.add(eName);
1069      add_prop(eIsDrum);      table.add(eIsDrum);
1070      add_prop(eMIDIBank);      table.add(eMIDIBank);
1071      add_prop(eMIDIProgram);      table.add(eMIDIProgram);
1072      add_prop(eAttenuation);      table.add(eAttenuation);
1073      add_prop(eGainPlus6);      table.add(eGainPlus6);
1074      add_prop(eEffectSend);      table.add(eEffectSend);
1075      add_prop(eFineTune);      table.add(eFineTune);
1076      add_prop(ePitchbendRange);      table.add(ePitchbendRange);
1077      add_prop(ePianoReleaseMode);      table.add(ePianoReleaseMode);
1078      add_prop(eDimensionKeyRangeLow);      table.add(eDimensionKeyRangeLow);
1079      add_prop(eDimensionKeyRangeHigh);      table.add(eDimensionKeyRangeHigh);
   
     eDimensionKeyRangeLow.signal_value_changed().connect(  
         sigc::mem_fun(*this, &InstrumentProps::key_range_low_changed));  
     eDimensionKeyRangeHigh.signal_value_changed().connect(  
         sigc::mem_fun(*this, &InstrumentProps::key_range_high_changed));  
1080    
1081      add(vbox);      add(vbox);
1082      table.set_border_width(5);      table.set_border_width(5);
# Line 696  InstrumentProps::InstrumentProps() Line 1100  InstrumentProps::InstrumentProps()
1100    
1101  void InstrumentProps::set_instrument(gig::Instrument* instrument)  void InstrumentProps::set_instrument(gig::Instrument* instrument)
1102  {  {
1103      update_gui = false;      this->instrument = instrument;
1104      eName.set_ptr(&instrument->pInfo->Name);  
1105      eIsDrum.set_ptr(&instrument->IsDrum);      update_model++;
1106      eMIDIBank.set_ptr(&instrument->MIDIBank);      eName.set_value(instrument->pInfo->Name);
1107      eMIDIProgram.set_ptr(&instrument->MIDIProgram);      eIsDrum.set_value(instrument->IsDrum);
1108      eAttenuation.set_ptr(&instrument->Attenuation);      eMIDIBank.set_value(instrument->MIDIBank);
1109      eGainPlus6.set_ptr(&instrument->Attenuation);      eMIDIProgram.set_value(instrument->MIDIProgram);
1110      eEffectSend.set_ptr(&instrument->EffectSend);      eAttenuation.set_value(instrument->Attenuation);
1111      eFineTune.set_ptr(&instrument->FineTune);      eGainPlus6.set_value(instrument->Attenuation);
1112      ePitchbendRange.set_ptr(&instrument->PitchbendRange);      eEffectSend.set_value(instrument->EffectSend);
1113      ePianoReleaseMode.set_ptr(&instrument->PianoReleaseMode);      eFineTune.set_value(instrument->FineTune);
1114      eDimensionKeyRangeLow.set_ptr(&instrument->DimensionKeyRange.low);      ePitchbendRange.set_value(instrument->PitchbendRange);
1115      eDimensionKeyRangeHigh.set_ptr(&instrument->DimensionKeyRange.high);      ePianoReleaseMode.set_value(instrument->PianoReleaseMode);
1116      update_gui = true;      eDimensionKeyRangeLow.set_value(instrument->DimensionKeyRange.low);
1117        eDimensionKeyRangeHigh.set_value(instrument->DimensionKeyRange.high);
1118        update_model--;
1119  }  }
1120    
1121  void InstrumentProps::key_range_low_changed()  sigc::signal<void>& InstrumentProps::signal_instrument_changed()
1122  {  {
1123      double l = eDimensionKeyRangeLow.get_value();      return instrument_changed;
     double h = eDimensionKeyRangeHigh.get_value();  
     if (h < l) eDimensionKeyRangeHigh.set_value(l);  
1124  }  }
1125    
1126  void InstrumentProps::key_range_high_changed()  void MainWindow::file_changed()
1127  {  {
1128      double l = eDimensionKeyRangeLow.get_value();      if (file && !file_is_changed) {
1129      double h = eDimensionKeyRangeHigh.get_value();          set_title("*" + get_title());
1130      if (h < l) eDimensionKeyRangeLow.set_value(h);          file_is_changed = true;
1131        }
1132  }  }
1133    
1134  void MainWindow::load_gig(gig::File* gig, const char* filename)  void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)
1135  {  {
1136      file = gig;      file = 0;
1137        set_file_is_shared(isSharedInstrument);
1138    
1139      if (filename) {      this->filename = filename ? filename : _("Unsaved Gig File");
1140          const char *basename = strrchr(filename, '/');      set_title(Glib::filename_display_basename(this->filename));
1141          basename = basename ? basename + 1 : filename;      file_has_name = filename;
1142          set_title(basename);      file_is_changed = false;
     } else {  
         set_title("unnamed");  
     }  
1143    
1144      propDialog.set_info(gig->pInfo);      propDialog.set_info(gig->pInfo);
1145    
# Line 785  void MainWindow::load_gig(gig::File* gig Line 1188  void MainWindow::load_gig(gig::File* gig
1188          }          }
1189      }      }
1190    
1191        file = gig;
1192    
1193      // select the first instrument      // select the first instrument
1194      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1195      tree_sel_ref->select(Gtk::TreePath("0"));      tree_sel_ref->select(Gtk::TreePath("0"));
# Line 792  void MainWindow::load_gig(gig::File* gig Line 1197  void MainWindow::load_gig(gig::File* gig
1197    
1198  void MainWindow::show_instr_props()  void MainWindow::show_instr_props()
1199  {  {
1200      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      gig::Instrument* instrument = get_instrument();
1201      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      if (instrument)
     if (it)  
1202      {      {
1203          Gtk::TreeModel::Row row = *it;          instrumentProps.set_instrument(instrument);
1204          if (row[m_Columns.m_col_instr])          instrumentProps.show();
1205          {          instrumentProps.deiconify();
             instrumentProps.set_instrument(row[m_Columns.m_col_instr]);  
             instrumentProps.show();  
             instrumentProps.deiconify();  
         }  
1206      }      }
1207  }  }
1208    
1209    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  void MainWindow::on_button_release(GdkEventButton* button)  void MainWindow::on_button_release(GdkEventButton* button)
1221  {  {
1222      if (button->type == GDK_2BUTTON_PRESS) {      if (button->type == GDK_2BUTTON_PRESS) {
# Line 858  void MainWindow::on_action_add_instrumen Line 1269  void MainWindow::on_action_add_instrumen
1269      Gtk::TreeModel::Row rowInstr = *iterInstr;      Gtk::TreeModel::Row rowInstr = *iterInstr;
1270      rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();      rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1271      rowInstr[m_Columns.m_col_instr] = instrument;      rowInstr[m_Columns.m_col_instr] = instrument;
1272        file_changed();
1273  }  }
1274    
1275  void MainWindow::on_action_remove_instrument() {  void MainWindow::on_action_remove_instrument() {
1276      if (!file) return;      if (!file) return;
1277        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      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
1289      Gtk::TreeModel::iterator it = sel->get_selected();      Gtk::TreeModel::iterator it = sel->get_selected();
1290      if (it) {      if (it) {
# Line 872  void MainWindow::on_action_remove_instru Line 1295  void MainWindow::on_action_remove_instru
1295              if (instr) file->DeleteInstrument(instr);              if (instr) file->DeleteInstrument(instr);
1296              // remove respective row from instruments tree view              // remove respective row from instruments tree view
1297              m_refTreeModel->erase(it);              m_refTreeModel->erase(it);
1298                file_changed();
1299          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1300              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1301              msg.run();              msg.run();
# Line 900  void MainWindow::on_action_add_group() { Line 1324  void MainWindow::on_action_add_group() {
1324      rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();      rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1325      rowGroup[m_SamplesModel.m_col_sample] = NULL;      rowGroup[m_SamplesModel.m_col_sample] = NULL;
1326      rowGroup[m_SamplesModel.m_col_group] = group;      rowGroup[m_SamplesModel.m_col_group] = group;
1327        file_changed();
1328  }  }
1329    
1330  void MainWindow::on_action_add_sample() {  void MainWindow::on_action_add_sample() {
# Line 925  void MainWindow::on_action_add_sample() Line 1350  void MainWindow::on_action_add_sample()
1350      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1351      dialog.set_select_multiple(true);      dialog.set_select_multiple(true);
1352      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1353      const char* supportedFileTypes[] = {      const char* const supportedFileTypes[] = {
1354          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1355          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1356          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
# Line 955  void MainWindow::on_action_add_sample() Line 1380  void MainWindow::on_action_add_sample()
1380                  int bitdepth;                  int bitdepth;
1381                  switch (info.format & 0xff) {                  switch (info.format & 0xff) {
1382                      case SF_FORMAT_PCM_S8:                      case SF_FORMAT_PCM_S8:
                         bitdepth = 16; // we simply convert to 16 bit for now  
                         break;  
1383                      case SF_FORMAT_PCM_16:                      case SF_FORMAT_PCM_16:
1384                        case SF_FORMAT_PCM_U8:
1385                          bitdepth = 16;                          bitdepth = 16;
1386                          break;                          break;
1387                      case SF_FORMAT_PCM_24:                      case SF_FORMAT_PCM_24:
                         bitdepth = 32; // we simply convert to 32 bit for now  
                         break;  
1388                      case SF_FORMAT_PCM_32:                      case SF_FORMAT_PCM_32:
                         bitdepth = 32;  
                         break;  
                     case SF_FORMAT_PCM_U8:  
                         bitdepth = 16; // we simply convert to 16 bit for now  
                         break;  
1389                      case SF_FORMAT_FLOAT:                      case SF_FORMAT_FLOAT:
                         bitdepth = 32;  
                         break;  
1390                      case SF_FORMAT_DOUBLE:                      case SF_FORMAT_DOUBLE:
1391                          bitdepth = 32; // I guess we will always truncate this to 32 bit                          bitdepth = 24;
1392                          break;                          break;
1393                      default:                      default:
1394                          sf_close(hFile); // close sound file                          sf_close(hFile); // close sound file
# Line 982  void MainWindow::on_action_add_sample() Line 1397  void MainWindow::on_action_add_sample()
1397                  // add a new sample to the .gig file                  // add a new sample to the .gig file
1398                  gig::Sample* sample = file->AddSample();                  gig::Sample* sample = file->AddSample();
1399                  // file name without path                  // file name without path
1400                  sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw();                  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                  sample->Channels = info.channels;                  sample->Channels = info.channels;
1410                  sample->BitDepth = bitdepth;                  sample->BitDepth = bitdepth;
1411                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1412                  sample->SamplesPerSecond = info.samplerate;                  sample->SamplesPerSecond = info.samplerate;
1413                    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    #if HAVE_SF_INSTRUMENT_LOOPS
1424                        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    #endif
1444                    }
1445    
1446                  // schedule resizing the sample (which will be done                  // schedule resizing the sample (which will be done
1447                  // physically when File::Save() is called)                  // physically when File::Save() is called)
1448                  sample->Resize(info.frames);                  sample->Resize(info.frames);
# Line 1002  void MainWindow::on_action_add_sample() Line 1458  void MainWindow::on_action_add_sample()
1458                  Gtk::TreeModel::iterator iterSample =                  Gtk::TreeModel::iterator iterSample =
1459                      m_refSamplesTreeModel->append(row.children());                      m_refSamplesTreeModel->append(row.children());
1460                  Gtk::TreeModel::Row rowSample = *iterSample;                  Gtk::TreeModel::Row rowSample = *iterSample;
1461                  rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();                  rowSample[m_SamplesModel.m_col_name]   = filename;
1462                  rowSample[m_SamplesModel.m_col_sample] = sample;                  rowSample[m_SamplesModel.m_col_sample] = sample;
1463                  rowSample[m_SamplesModel.m_col_group]  = NULL;                  rowSample[m_SamplesModel.m_col_group]  = NULL;
1464                  // close sound file                  // close sound file
1465                  sf_close(hFile);                  sf_close(hFile);
1466                    file_changed();
1467              } catch (std::string what) { // remember the files that made trouble (and their cause)              } catch (std::string what) { // remember the files that made trouble (and their cause)
1468                  if (error_files.size()) error_files += "\n";                  if (error_files.size()) error_files += "\n";
1469                  error_files += *iter += " (" + what + ")";                  error_files += *iter += " (" + what + ")";
# Line 1014  void MainWindow::on_action_add_sample() Line 1471  void MainWindow::on_action_add_sample()
1471          }          }
1472          // show error message box when some file(s) could not be opened / added          // show error message box when some file(s) could not be opened / added
1473          if (error_files.size()) {          if (error_files.size()) {
1474              Glib::ustring txt = "Could not add the following sample(s):\n" + error_files;              Glib::ustring txt = _("Could not add the following sample(s):\n") + error_files;
1475              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1476              msg.run();              msg.run();
1477          }          }
# Line 1040  void MainWindow::on_action_remove_sample Line 1497  void MainWindow::on_action_remove_sample
1497                       pSample; pSample = group->GetNextSample()) {                       pSample; pSample = group->GetNextSample()) {
1498                      members.push_back(pSample);                      members.push_back(pSample);
1499                  }                  }
1500                    // notify everybody that we're going to remove these samples
1501                    samples_to_be_removed_signal.emit(members);
1502                  // delete the group in the .gig file including the                  // delete the group in the .gig file including the
1503                  // samples that belong to the group                  // samples that belong to the group
1504                  file->DeleteGroup(group);                  file->DeleteGroup(group);
1505                    // notify that we're done with removal
1506                    samples_removed_signal.emit();
1507                  // if sample(s) were just previously added, remove                  // if sample(s) were just previously added, remove
1508                  // them from the import queue                  // them from the import queue
1509                  for (std::list<gig::Sample*>::iterator member = members.begin();                  for (std::list<gig::Sample*>::iterator member = members.begin();
# Line 1057  void MainWindow::on_action_remove_sample Line 1518  void MainWindow::on_action_remove_sample
1518                          }                          }
1519                      }                      }
1520                  }                  }
1521                    file_changed();
1522              } else if (sample) {              } else if (sample) {
1523                    // 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                  // remove sample from the .gig file                  // remove sample from the .gig file
1528                  file->DeleteSample(sample);                  file->DeleteSample(sample);
1529                    // notify that we're done with removal
1530                    samples_removed_signal.emit();
1531                  // if sample was just previously added, remove it from                  // if sample was just previously added, remove it from
1532                  // the import queue                  // the import queue
1533                  for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();                  for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
# Line 1071  void MainWindow::on_action_remove_sample Line 1539  void MainWindow::on_action_remove_sample
1539                          break;                          break;
1540                      }                      }
1541                  }                  }
1542                    dimreg_changed();
1543                    file_changed();
1544              }              }
1545              // remove respective row(s) from samples tree view              // remove respective row(s) from samples tree view
1546              m_refSamplesTreeModel->erase(it);              m_refSamplesTreeModel->erase(it);
1547          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1548                // pretend we're done with removal (i.e. to avoid dead locks)
1549                samples_removed_signal.emit();
1550                // show error message
1551              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1552              msg.run();              msg.run();
1553          }          }
1554      }      }
1555  }  }
1556    
1557    // 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  void MainWindow::on_sample_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,  void MainWindow::on_sample_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,
1567                                                    Gtk::SelectionData& selection_data, guint, guint)                                                    Gtk::SelectionData& selection_data, guint, guint)
1568  {  {
1569        if (!first_call_to_drag_data_get) return;
1570        first_call_to_drag_data_get = false;
1571    
1572      // get selected sample      // get selected sample
1573      gig::Sample* sample = NULL;      gig::Sample* sample = NULL;
1574      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
# Line 1101  void MainWindow::on_sample_label_drop_dr Line 1586  void MainWindow::on_sample_label_drop_dr
1586      const Glib::RefPtr<Gdk::DragContext>& context, int, int,      const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1587      const Gtk::SelectionData& selection_data, guint, guint time)      const Gtk::SelectionData& selection_data, guint, guint time)
1588  {  {
     gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();  
1589      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1590    
1591      if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {      if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
1592          if (sample != dimregion->pSample) {          std::cout << "Drop received sample \"" <<
1593              dimregion->pSample = sample;              sample->pInfo->Name << "\"" << std::endl;
1594              dimreg_edit.wSample->set_text(dimregion->pSample->pInfo->Name.c_str());          // drop success
1595              std::cout << "Drop received sample \"" <<          context->drop_reply(true, time);
1596                  dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;  
1597              // drop success          //TODO: we should better move most of the following code to DimRegionEdit::set_sample()
1598              context->drop_reply(true, time);  
1599              return;          // 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            // 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            }
1612            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                        gig::Sample* oldref = d->pSample;
1638                        d->pSample = NULL;
1639                        sample_ref_changed_signal.emit(oldref, NULL);
1640                    }
1641                }
1642            }
1643    
1644            // notify we're done with altering
1645            region_changed_signal.emit(region);
1646    
1647            file_changed();
1648    
1649            return;
1650      }      }
1651      // drop failed      // drop failed
1652      context->drop_reply(false, time);      context->drop_reply(false, time);
# Line 1127  void MainWindow::sample_name_changed(con Line 1660  void MainWindow::sample_name_changed(con
1660      gig::Group* group   = row[m_SamplesModel.m_col_group];      gig::Group* group   = row[m_SamplesModel.m_col_group];
1661      gig::Sample* sample = row[m_SamplesModel.m_col_sample];      gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1662      if (group) {      if (group) {
1663          group->Name = name;          if (group->Name != name) {
1664                group->Name = name;
1665                printf("group name changed\n");
1666                file_changed();
1667            }
1668      } else if (sample) {      } else if (sample) {
1669          sample->pInfo->Name = name.raw();          if (sample->pInfo->Name != name.raw()) {
1670                sample->pInfo->Name = name.raw();
1671                printf("sample name changed\n");
1672                file_changed();
1673            }
1674      }      }
1675  }  }
1676    
# Line 1139  void MainWindow::instrument_name_changed Line 1680  void MainWindow::instrument_name_changed
1680      Gtk::TreeModel::Row row = *iter;      Gtk::TreeModel::Row row = *iter;
1681      Glib::ustring name = row[m_Columns.m_col_name];      Glib::ustring name = row[m_Columns.m_col_name];
1682      gig::Instrument* instrument = row[m_Columns.m_col_instr];      gig::Instrument* instrument = row[m_Columns.m_col_instr];
1683      if (instrument) instrument->pInfo->Name = name.raw();      if (instrument && instrument->pInfo->Name != name.raw()) {
1684            instrument->pInfo->Name = name.raw();
1685            file_changed();
1686        }
1687    }
1688    
1689    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    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {
1706        return file_structure_to_be_changed_signal;
1707    }
1708    
1709    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_changed() {
1710        return file_structure_changed_signal;
1711    }
1712    
1713    sigc::signal<void, std::list<gig::Sample*> >& MainWindow::signal_samples_to_be_removed() {
1714        return samples_to_be_removed_signal;
1715    }
1716    
1717    sigc::signal<void>& MainWindow::signal_samples_removed() {
1718        return samples_removed_signal;
1719    }
1720    
1721    sigc::signal<void, gig::Region*>& MainWindow::signal_region_to_be_changed() {
1722        return region_to_be_changed_signal;
1723    }
1724    
1725    sigc::signal<void, gig::Region*>& MainWindow::signal_region_changed() {
1726        return region_changed_signal;
1727    }
1728    
1729    sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& MainWindow::signal_sample_ref_changed() {
1730        return sample_ref_changed_signal;
1731    }
1732    
1733    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_to_be_changed() {
1734        return dimreg_to_be_changed_signal;
1735    }
1736    
1737    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_changed() {
1738        return dimreg_changed_signal;
1739  }  }

Legend:
Removed from v.1225  
changed lines
  Added in v.1582

  ViewVC Help
Powered by ViewVC