/[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 1261 by persson, Thu Jul 5 17:12:20 2007 UTC revision 1415 by schoenebeck, Sat Oct 13 13:14:10 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    #include "global.h"
30    
31  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2  #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 115  MainWindow::MainWindow() Line 130  MainWindow::MainWindow()
130                           *this, &MainWindow::on_action_quit));                           *this, &MainWindow::on_action_quit));
131      actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));      actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));
132    
133        actionGroup->add(Gtk::Action::create("MenuView", _("_View")));
134        Glib::RefPtr<Gtk::ToggleAction> toggle_action =
135            Gtk::ToggleAction::create("Statusbar", _("_Statusbar"));
136        toggle_action->set_active(true);
137        actionGroup->add(toggle_action,
138                         sigc::mem_fun(
139                             *this, &MainWindow::on_action_view_status_bar));
140    
141      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);
142      actionGroup->add(Gtk::Action::create("MenuHelp",      actionGroup->add(Gtk::Action::create("MenuHelp",
143                                           action->property_label()));                                           action->property_label()));
# Line 170  MainWindow::MainWindow() Line 193  MainWindow::MainWindow()
193          "    </menu>"          "    </menu>"
194          "    <menu action='MenuInstrument'>"          "    <menu action='MenuInstrument'>"
195          "    </menu>"          "    </menu>"
196            "    <menu action='MenuView'>"
197            "      <menuitem action='Statusbar'/>"
198            "    </menu>"
199  #ifdef ABOUT_DIALOG  #ifdef ABOUT_DIALOG
200          "    <menu action='MenuHelp'>"          "    <menu action='MenuHelp'>"
201          "      <menuitem action='About'/>"          "      <menuitem action='About'/>"
# Line 199  MainWindow::MainWindow() Line 225  MainWindow::MainWindow()
225      m_VBox.pack_start(m_HPaned);      m_VBox.pack_start(m_HPaned);
226      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
227      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
228        m_VBox.pack_start(m_StatusBar, Gtk::PACK_SHRINK);
229    
230        // Status Bar:
231        m_StatusBar.pack_start(m_AttachedStateLabel, Gtk::PACK_SHRINK);
232        m_StatusBar.pack_start(m_AttachedStateImage, Gtk::PACK_SHRINK);
233        m_StatusBar.show();
234    
235      m_RegionChooser.signal_region_selected().connect(      m_RegionChooser.signal_region_selected().connect(
236          sigc::mem_fun(*this, &MainWindow::region_changed) );          sigc::mem_fun(*this, &MainWindow::region_changed) );
# Line 234  MainWindow::MainWindow() Line 266  MainWindow::MainWindow()
266      std::list<Gtk::TargetEntry> drag_target_gig_sample;      std::list<Gtk::TargetEntry> drag_target_gig_sample;
267      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
268      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
269        m_TreeViewSamples.signal_drag_begin().connect(
270            sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)
271        );
272      m_TreeViewSamples.signal_drag_data_get().connect(      m_TreeViewSamples.signal_drag_data_get().connect(
273          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
274      );      );
# Line 242  MainWindow::MainWindow() Line 277  MainWindow::MainWindow()
277          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
278      );      );
279      dimreg_edit.signal_dimreg_changed().connect(      dimreg_edit.signal_dimreg_changed().connect(
280          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::hide(sigc::mem_fun(*this, &MainWindow::file_changed)));
281      m_RegionChooser.signal_instrument_changed().connect(      m_RegionChooser.signal_instrument_changed().connect(
282          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
283      m_DimRegionChooser.signal_region_changed().connect(      m_DimRegionChooser.signal_region_changed().connect(
284          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
285      instrumentProps.signal_instrument_changed().connect(      instrumentProps.signal_instrument_changed().connect(
286          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
287    
288        dimreg_edit.signal_dimreg_to_be_changed().connect(
289            dimreg_to_be_changed_signal.make_slot());
290        dimreg_edit.signal_dimreg_changed().connect(
291            dimreg_changed_signal.make_slot());
292        dimreg_edit.signal_sample_ref_changed().connect(
293            sample_ref_changed_signal.make_slot());
294    
295        m_RegionChooser.signal_instrument_struct_to_be_changed().connect(
296            sigc::hide(
297                sigc::bind(
298                    file_structure_to_be_changed_signal.make_slot(),
299                    sigc::ref(this->file)
300                )
301            )
302        );
303        m_RegionChooser.signal_instrument_struct_changed().connect(
304            sigc::hide(
305                sigc::bind(
306                    file_structure_changed_signal.make_slot(),
307                    sigc::ref(this->file)
308                )
309            )
310        );
311        m_RegionChooser.signal_region_to_be_changed().connect(
312            region_to_be_changed_signal.make_slot());
313        m_RegionChooser.signal_region_changed_signal().connect(
314            region_changed_signal.make_slot());
315    
316      file = 0;      file = 0;
317      file_is_changed = false;      file_is_changed = false;
318        set_file_is_shared(false);
319    
320      show_all_children();      show_all_children();
321    
322        // start with a new gig file by default
323        on_action_file_new();
324  }  }
325    
326  MainWindow::~MainWindow()  MainWindow::~MainWindow()
# Line 261  MainWindow::~MainWindow() Line 329  MainWindow::~MainWindow()
329    
330  bool MainWindow::on_delete_event(GdkEventAny* event)  bool MainWindow::on_delete_event(GdkEventAny* event)
331  {  {
332      return file_is_changed && !close_confirmation_dialog();      return !file_is_shared && file_is_changed && !close_confirmation_dialog();
333  }  }
334    
335  void MainWindow::on_action_quit()  void MainWindow::on_action_quit()
336  {  {
337      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
338      hide();      hide();
339  }  }
340    
# Line 380  void MainWindow::__clear() { Line 448  void MainWindow::__clear() {
448      m_refTreeModel->clear();      m_refTreeModel->clear();
449      m_refSamplesTreeModel->clear();      m_refSamplesTreeModel->clear();
450      // free libgig's gig::File instance      // free libgig's gig::File instance
451      if (file) {      if (file && !file_is_shared) delete file;
452          delete file;      file = NULL;
453          file = NULL;      set_file_is_shared(false);
     }  
454  }  }
455    
456  void MainWindow::on_action_file_new()  void MainWindow::on_action_file_new()
457  {  {
458      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
459    
460        if (file_is_shared && !leaving_shared_mode_dialog()) return;
461    
462      // clear all GUI elements      // clear all GUI elements
463      __clear();      __clear();
# Line 407  bool MainWindow::close_confirmation_dial Line 476  bool MainWindow::close_confirmation_dial
476                                   Glib::filename_display_basename(filename).c_str());                                   Glib::filename_display_basename(filename).c_str());
477      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
478      g_free(msg);      g_free(msg);
479    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
480      dialog.set_secondary_text(_("If you close without saving, your changes will be lost."));      dialog.set_secondary_text(_("If you close without saving, your changes will be lost."));
481    #endif
482      dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);      dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
483      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
484      dialog.add_button(file_has_name ? Gtk::Stock::SAVE : Gtk::Stock::SAVE_AS, Gtk::RESPONSE_YES);      dialog.add_button(file_has_name ? Gtk::Stock::SAVE : Gtk::Stock::SAVE_AS, Gtk::RESPONSE_YES);
485      dialog.set_default_response(Gtk::RESPONSE_YES);      dialog.set_default_response(Gtk::RESPONSE_YES);
486      int response = dialog.run();      int response = dialog.run();
487        dialog.hide();
488      if (response == Gtk::RESPONSE_YES) return file_save();      if (response == Gtk::RESPONSE_YES) return file_save();
489      return response != Gtk::RESPONSE_CANCEL;      return response != Gtk::RESPONSE_CANCEL;
490  }  }
491    
492    bool MainWindow::leaving_shared_mode_dialog() {
493        Glib::ustring msg = _("Detach from sampler and proceed working stand-alone?");
494        Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
495    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
496        dialog.set_secondary_text(
497            _("If you proceed to work on another instrument file, it won't be "
498              "used by the sampler until you tell the sampler explicitly to "
499              "load it.")
500       );
501    #endif
502        dialog.add_button(_("_Yes, Detach"), Gtk::RESPONSE_YES);
503        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
504        dialog.set_default_response(Gtk::RESPONSE_CANCEL);
505        int response = dialog.run();
506        dialog.hide();
507        return response == Gtk::RESPONSE_YES;
508    }
509    
510  void MainWindow::on_action_file_open()  void MainWindow::on_action_file_open()
511  {  {
512      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
513    
514        if (file_is_shared && !leaving_shared_mode_dialog()) return;
515    
516      Gtk::FileChooserDialog dialog(*this, _("Open file"));      Gtk::FileChooserDialog dialog(*this, _("Open file"));
517      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
# Line 434  void MainWindow::on_action_file_open() Line 526  void MainWindow::on_action_file_open()
526      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
527          std::string filename = dialog.get_filename();          std::string filename = dialog.get_filename();
528          printf("filename=%s\n", filename.c_str());          printf("filename=%s\n", filename.c_str());
         __clear();  
529          printf("on_action_file_open self=%x\n", Glib::Thread::self());          printf("on_action_file_open self=%x\n", Glib::Thread::self());
530          load_file(filename.c_str());          load_file(filename.c_str());
531          current_dir = Glib::path_get_dirname(filename);          current_dir = Glib::path_get_dirname(filename);
# Line 443  void MainWindow::on_action_file_open() Line 534  void MainWindow::on_action_file_open()
534    
535  void MainWindow::load_file(const char* name)  void MainWindow::load_file(const char* name)
536  {  {
537        __clear();
538      load_dialog = new LoadDialog("Loading...", *this);      load_dialog = new LoadDialog("Loading...", *this);
539      load_dialog->show_all();      load_dialog->show_all();
540      loader = new Loader(strdup(name));      loader = new Loader(strdup(name));
# Line 460  void MainWindow::load_instrument(gig::In Line 552  void MainWindow::load_instrument(gig::In
552          msg.run();          msg.run();
553          Gtk::Main::quit();          Gtk::Main::quit();
554      }      }
555        // clear all GUI elements
556        __clear();
557        // load the instrument
558      gig::File* pFile = (gig::File*) instr->GetParent();      gig::File* pFile = (gig::File*) instr->GetParent();
559      load_gig(pFile, 0 /*file name*/);      load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);
560      //TODO: automatically select the given instrument      //TODO: automatically select the given instrument
561  }  }
562    
# Line 483  void MainWindow::on_action_file_save() Line 578  void MainWindow::on_action_file_save()
578      file_save();      file_save();
579  }  }
580    
581  bool MainWindow::file_save()  bool MainWindow::check_if_savable()
582  {  {
583      if (!file) return false;      if (!file) return false;
584      if (!file_has_name) return file_save_as();  
585        if (!file->GetFirstSample()) {
586            Gtk::MessageDialog(*this, _("The file could not be saved "
587                                        "because it contains no samples"),
588                               false, Gtk::MESSAGE_ERROR).run();
589            return false;
590        }
591    
592        for (gig::Instrument* instrument = file->GetFirstInstrument() ; instrument ;
593             instrument = file->GetNextInstrument()) {
594            if (!instrument->GetFirstRegion()) {
595                Gtk::MessageDialog(*this, _("The file could not be saved "
596                                            "because there are instruments "
597                                            "that have no regions"),
598                                   false, Gtk::MESSAGE_ERROR).run();
599                return false;
600            }
601        }
602        return true;
603    }
604    
605    bool MainWindow::file_save()
606    {
607        if (!check_if_savable()) return false;
608        if (!file_is_shared && !file_has_name) return file_save_as();
609    
610      std::cout << "Saving file\n" << std::flush;      std::cout << "Saving file\n" << std::flush;
611        file_structure_to_be_changed_signal.emit(this->file);
612      try {      try {
613          file->Save();          file->Save();
614          if (file_is_changed) {          if (file_is_changed) {
# Line 496  bool MainWindow::file_save() Line 616  bool MainWindow::file_save()
616              file_is_changed = false;              file_is_changed = false;
617          }          }
618      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
619          Glib::ustring txt = "Could not save file: " + e.Message;          file_structure_changed_signal.emit(this->file);
620            Glib::ustring txt = _("Could not save file: ") + e.Message;
621          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
622          msg.run();          msg.run();
623          return false;          return false;
624      }      }
625      std::cout << "Saving file done\n" << std::flush;      std::cout << "Saving file done\n" << std::flush;
626      __import_queued_samples();      __import_queued_samples();
627        file_structure_changed_signal.emit(this->file);
628      return true;      return true;
629  }  }
630    
631  void MainWindow::on_action_file_save_as()  void MainWindow::on_action_file_save_as()
632  {  {
633        if (!check_if_savable()) return;
634      file_save_as();      file_save_as();
635  }  }
636    
637  bool MainWindow::file_save_as()  bool MainWindow::file_save_as()
638  {  {
     if (!file) return false;  
639      Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);      Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);
640      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
641      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
# Line 535  bool MainWindow::file_save_as() Line 657  bool MainWindow::file_save_as()
657      dialog.set_current_name(Glib::filename_display_basename(filename));      dialog.set_current_name(Glib::filename_display_basename(filename));
658    
659      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
660            file_structure_to_be_changed_signal.emit(this->file);
661          try {          try {
662              std::string filename = dialog.get_filename();              std::string filename = dialog.get_filename();
663              if (!Glib::str_has_suffix(filename, ".gig")) {              if (!Glib::str_has_suffix(filename, ".gig")) {
# Line 548  bool MainWindow::file_save_as() Line 671  bool MainWindow::file_save_as()
671              file_has_name = true;              file_has_name = true;
672              file_is_changed = false;              file_is_changed = false;
673          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
674              Glib::ustring txt = "Could not save file: " + e.Message;              file_structure_changed_signal.emit(this->file);
675                Glib::ustring txt = _("Could not save file: ") + e.Message;
676              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
677              msg.run();              msg.run();
678              return false;              return false;
679          }          }
680          __import_queued_samples();          __import_queued_samples();
681            file_structure_changed_signal.emit(this->file);
682          return true;          return true;
683      }      }
684      return false;      return false;
# Line 576  void MainWindow::__import_queued_samples Line 701  void MainWindow::__import_queued_samples
701              int bitdepth;              int bitdepth;
702              switch (info.format & 0xff) {              switch (info.format & 0xff) {
703                  case SF_FORMAT_PCM_S8:                  case SF_FORMAT_PCM_S8:
                     bitdepth = 16; // we simply convert to 16 bit for now  
                     break;  
704                  case SF_FORMAT_PCM_16:                  case SF_FORMAT_PCM_16:
705                    case SF_FORMAT_PCM_U8:
706                      bitdepth = 16;                      bitdepth = 16;
707                      break;                      break;
708                  case SF_FORMAT_PCM_24:                  case SF_FORMAT_PCM_24:
                     bitdepth = 32; // we simply convert to 32 bit for now  
                     break;  
709                  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;  
710                  case SF_FORMAT_FLOAT:                  case SF_FORMAT_FLOAT:
                     bitdepth = 32;  
                     break;  
711                  case SF_FORMAT_DOUBLE:                  case SF_FORMAT_DOUBLE:
712                      bitdepth = 32; // I guess we will always truncate this to 32 bit                      bitdepth = 24;
713                      break;                      break;
714                  default:                  default:
715                      sf_close(hFile); // close sound file                      sf_close(hFile); // close sound file
716                      throw std::string("format not supported"); // unsupported subformat (yet?)                      throw std::string("format not supported"); // unsupported subformat (yet?)
717              }              }
718              // allocate appropriate copy buffer (TODO: for now we copy  
719              // 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;  
720              switch (bitdepth) {              switch (bitdepth) {
721                  case 16:                  case 16: {
722                      buffer = new int8_t[2 * info.channels * info.frames];                      short* buffer = new short[bufsize * info.channels];
723                      // libsndfile does the conversion for us (if needed)                      sf_count_t cnt = info.frames;
724                      sf_readf_short(hFile, (short*) buffer, info.frames);                      while (cnt) {
725                            // libsndfile does the conversion for us (if needed)
726                            int n = sf_readf_short(hFile, buffer, bufsize);
727                            // write from buffer directly (physically) into .gig file
728                            iter->gig_sample->Write(buffer, n);
729                            cnt -= n;
730                        }
731                        delete[] buffer;
732                      break;                      break;
733                  case 32:                  }
734                      buffer = new int8_t[4 * info.channels * info.frames];                  case 24: {
735                      // libsndfile does the conversion for us (if needed)                      int* srcbuf = new int[bufsize * info.channels];
736                      sf_readf_int(hFile, (int*) buffer, info.frames);                      uint8_t* dstbuf = new uint8_t[bufsize * 3 * info.channels];
737                        sf_count_t cnt = info.frames;
738                        while (cnt) {
739                            // libsndfile returns 32 bits, convert to 24
740                            int n = sf_readf_int(hFile, srcbuf, bufsize);
741                            int j = 0;
742                            for (int i = 0 ; i < n * info.channels ; i++) {
743                                dstbuf[j++] = srcbuf[i] >> 8;
744                                dstbuf[j++] = srcbuf[i] >> 16;
745                                dstbuf[j++] = srcbuf[i] >> 24;
746                            }
747                            // write from buffer directly (physically) into .gig file
748                            iter->gig_sample->Write(dstbuf, n);
749                            cnt -= n;
750                        }
751                        delete[] srcbuf;
752                        delete[] dstbuf;
753                      break;                      break;
754                    }
755              }              }
             // write from buffer directly (physically) into .gig file  
             (*iter).gig_sample->Write(buffer, info.frames);  
756              // cleanup              // cleanup
757              sf_close(hFile);              sf_close(hFile);
             delete[] buffer;  
758              // on success we remove the sample from the import queue,              // on success we remove the sample from the import queue,
759              // otherwise keep it, maybe it works the next time ?              // otherwise keep it, maybe it works the next time ?
760              std::list<SampleImportItem>::iterator cur = iter;              std::list<SampleImportItem>::iterator cur = iter;
# Line 635  void MainWindow::__import_queued_samples Line 769  void MainWindow::__import_queued_samples
769      }      }
770      // show error message box when some sample(s) could not be imported      // show error message box when some sample(s) could not be imported
771      if (error_files.size()) {      if (error_files.size()) {
772          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;
773          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
774          msg.run();          msg.run();
775      }      }
# Line 712  void PropDialog::set_info(DLS::Info* inf Line 846  void PropDialog::set_info(DLS::Info* inf
846      entry[15].set_text(info->Subject);      entry[15].set_text(info->Subject);
847  }  }
848    
849    void InstrumentProps::add_prop(BoolEntry& boolentry)
850    {
851        table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,
852                     Gtk::FILL, Gtk::SHRINK);
853        rowno++;
854        boolentry.signal_changed_by_user().connect(instrument_changed.make_slot());
855    }
856    
857    void InstrumentProps::add_prop(BoolEntryPlus6& boolentry)
858    {
859        table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,
860                     Gtk::FILL, Gtk::SHRINK);
861        rowno++;
862        boolentry.signal_changed_by_user().connect(instrument_changed.make_slot());
863    }
864    
865  void InstrumentProps::add_prop(LabelWidget& prop)  void InstrumentProps::add_prop(LabelWidget& prop)
866  {  {
867      table.attach(prop.label, 0, 1, rowno, rowno + 1,      table.attach(prop.label, 0, 1, rowno, rowno + 1,
# Line 726  InstrumentProps::InstrumentProps() Line 876  InstrumentProps::InstrumentProps()
876      : table(2,1),      : table(2,1),
877        quitButton(Gtk::Stock::CLOSE),        quitButton(Gtk::Stock::CLOSE),
878        eName("Name"),        eName("Name"),
879        eIsDrum("IsDrum"),        eIsDrum("Is drum"),
880        eMIDIBank("MIDIBank", 0, 16383),        eMIDIBank("MIDI bank", 0, 16383),
881        eMIDIProgram("MIDIProgram"),        eMIDIProgram("MIDI program"),
882        eAttenuation("Attenuation", 0, 96, 0, 1),        eAttenuation("Attenuation", 0, 96, 0, 1),
883        eGainPlus6("Gain +6dB", eAttenuation, -6),        eGainPlus6("Gain +6dB", eAttenuation, -6),
884        eEffectSend("EffectSend", 0, 65535),        eEffectSend("Effect send", 0, 65535),
885        eFineTune("FineTune", -8400, 8400),        eFineTune("Fine tune", -8400, 8400),
886        ePitchbendRange("PitchbendRange", 0, 12),        ePitchbendRange("Pitchbend range", 0, 12),
887        ePianoReleaseMode("PianoReleaseMode"),        ePianoReleaseMode("Piano release mode"),
888        eDimensionKeyRangeLow("DimensionKeyRangeLow"),        eDimensionKeyRangeLow("Dimension key range low"),
889        eDimensionKeyRangeHigh("DimensionKeyRangeHigh")        eDimensionKeyRangeHigh("Dimension key range high")
890  {  {
891      set_title("Instrument properties");      set_title("Instrument properties");
892    
# Line 813  void InstrumentProps::key_range_high_cha Line 963  void InstrumentProps::key_range_high_cha
963      if (h < l) eDimensionKeyRangeLow.set_value(h);      if (h < l) eDimensionKeyRangeLow.set_value(h);
964  }  }
965    
966  sigc::signal<void> InstrumentProps::signal_instrument_changed()  sigc::signal<void>& InstrumentProps::signal_instrument_changed()
967  {  {
968      return instrument_changed;      return instrument_changed;
969  }  }
# Line 826  void MainWindow::file_changed() Line 976  void MainWindow::file_changed()
976      }      }
977  }  }
978    
979  void MainWindow::load_gig(gig::File* gig, const char* filename)  void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)
980  {  {
981      file = 0;      file = 0;
982        set_file_is_shared(isSharedInstrument);
983    
984      this->filename = filename ? filename : _("Unsaved Gig File");      this->filename = filename ? filename : _("Unsaved Gig File");
985      set_title(Glib::filename_display_basename(this->filename));      set_title(Glib::filename_display_basename(this->filename));
# Line 905  void MainWindow::show_instr_props() Line 1056  void MainWindow::show_instr_props()
1056      }      }
1057  }  }
1058    
1059    void MainWindow::on_action_view_status_bar() {
1060        Gtk::CheckMenuItem* item =
1061            dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuView/Statusbar"));
1062        if (!item) {
1063            std::cerr << "/MenuBar/MenuView/Statusbar == NULL\n";
1064            return;
1065        }
1066        if (item->get_active()) m_StatusBar.show();
1067        else                    m_StatusBar.hide();
1068    }
1069    
1070  void MainWindow::on_button_release(GdkEventButton* button)  void MainWindow::on_button_release(GdkEventButton* button)
1071  {  {
1072      if (button->type == GDK_2BUTTON_PRESS) {      if (button->type == GDK_2BUTTON_PRESS) {
# Line 962  void MainWindow::on_action_add_instrumen Line 1124  void MainWindow::on_action_add_instrumen
1124    
1125  void MainWindow::on_action_remove_instrument() {  void MainWindow::on_action_remove_instrument() {
1126      if (!file) return;      if (!file) return;
1127        if (file_is_shared) {
1128            Gtk::MessageDialog msg(
1129                *this,
1130                 _("You cannot delete an instrument from this file, since it's "
1131                   "currently used by the sampler."),
1132                 false, Gtk::MESSAGE_INFO
1133            );
1134            msg.run();
1135            return;
1136        }
1137    
1138      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
1139      Gtk::TreeModel::iterator it = sel->get_selected();      Gtk::TreeModel::iterator it = sel->get_selected();
1140      if (it) {      if (it) {
# Line 1027  void MainWindow::on_action_add_sample() Line 1200  void MainWindow::on_action_add_sample()
1200      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1201      dialog.set_select_multiple(true);      dialog.set_select_multiple(true);
1202      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1203      const char* supportedFileTypes[] = {      const char* const supportedFileTypes[] = {
1204          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1205          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1206          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
# Line 1057  void MainWindow::on_action_add_sample() Line 1230  void MainWindow::on_action_add_sample()
1230                  int bitdepth;                  int bitdepth;
1231                  switch (info.format & 0xff) {                  switch (info.format & 0xff) {
1232                      case SF_FORMAT_PCM_S8:                      case SF_FORMAT_PCM_S8:
                         bitdepth = 16; // we simply convert to 16 bit for now  
                         break;  
1233                      case SF_FORMAT_PCM_16:                      case SF_FORMAT_PCM_16:
1234                        case SF_FORMAT_PCM_U8:
1235                          bitdepth = 16;                          bitdepth = 16;
1236                          break;                          break;
1237                      case SF_FORMAT_PCM_24:                      case SF_FORMAT_PCM_24:
                         bitdepth = 32; // we simply convert to 32 bit for now  
                         break;  
1238                      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;  
1239                      case SF_FORMAT_FLOAT:                      case SF_FORMAT_FLOAT:
                         bitdepth = 32;  
                         break;  
1240                      case SF_FORMAT_DOUBLE:                      case SF_FORMAT_DOUBLE:
1241                          bitdepth = 32; // I guess we will always truncate this to 32 bit                          bitdepth = 24;
1242                          break;                          break;
1243                      default:                      default:
1244                          sf_close(hFile); // close sound file                          sf_close(hFile); // close sound file
# Line 1084  void MainWindow::on_action_add_sample() Line 1247  void MainWindow::on_action_add_sample()
1247                  // add a new sample to the .gig file                  // add a new sample to the .gig file
1248                  gig::Sample* sample = file->AddSample();                  gig::Sample* sample = file->AddSample();
1249                  // file name without path                  // file name without path
1250                  sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw();                  Glib::ustring filename = Glib::filename_display_basename(*iter);
1251                    // remove file extension if there is one
1252                    for (int i = 0; supportedFileTypes[i]; i++) {
1253                        if (Glib::str_has_suffix(filename, supportedFileTypes[i] + 1)) {
1254                            filename.erase(filename.length() - strlen(supportedFileTypes[i] + 1));
1255                            break;
1256                        }
1257                    }
1258                    sample->pInfo->Name = filename;
1259                  sample->Channels = info.channels;                  sample->Channels = info.channels;
1260                  sample->BitDepth = bitdepth;                  sample->BitDepth = bitdepth;
1261                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1262                  sample->SamplesPerSecond = info.samplerate;                  sample->SamplesPerSecond = info.samplerate;
1263                    sample->AverageBytesPerSecond = sample->FrameSize * sample->SamplesPerSecond;
1264                    sample->BlockAlign = sample->FrameSize;
1265                    sample->SamplesTotal = info.frames;
1266    
1267                    SF_INSTRUMENT instrument;
1268                    if (sf_command(hFile, SFC_GET_INSTRUMENT,
1269                                   &instrument, sizeof(instrument)) != SF_FALSE)
1270                    {
1271                        sample->MIDIUnityNote = instrument.basenote;
1272    
1273    #if HAVE_SF_INSTRUMENT_LOOPS
1274                        if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
1275                            sample->Loops = 1;
1276    
1277                            switch (instrument.loops[0].mode) {
1278                            case SF_LOOP_FORWARD:
1279                                sample->LoopType = gig::loop_type_normal;
1280                                break;
1281                            case SF_LOOP_BACKWARD:
1282                                sample->LoopType = gig::loop_type_backward;
1283                                break;
1284                            case SF_LOOP_ALTERNATING:
1285                                sample->LoopType = gig::loop_type_bidirectional;
1286                                break;
1287                            }
1288                            sample->LoopStart = instrument.loops[0].start;
1289                            sample->LoopEnd = instrument.loops[0].end;
1290                            sample->LoopPlayCount = instrument.loops[0].count;
1291                            sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
1292                        }
1293    #endif
1294                    }
1295    
1296                  // schedule resizing the sample (which will be done                  // schedule resizing the sample (which will be done
1297                  // physically when File::Save() is called)                  // physically when File::Save() is called)
1298                  sample->Resize(info.frames);                  sample->Resize(info.frames);
# Line 1104  void MainWindow::on_action_add_sample() Line 1308  void MainWindow::on_action_add_sample()
1308                  Gtk::TreeModel::iterator iterSample =                  Gtk::TreeModel::iterator iterSample =
1309                      m_refSamplesTreeModel->append(row.children());                      m_refSamplesTreeModel->append(row.children());
1310                  Gtk::TreeModel::Row rowSample = *iterSample;                  Gtk::TreeModel::Row rowSample = *iterSample;
1311                  rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();                  rowSample[m_SamplesModel.m_col_name]   = filename;
1312                  rowSample[m_SamplesModel.m_col_sample] = sample;                  rowSample[m_SamplesModel.m_col_sample] = sample;
1313                  rowSample[m_SamplesModel.m_col_group]  = NULL;                  rowSample[m_SamplesModel.m_col_group]  = NULL;
1314                  // close sound file                  // close sound file
# Line 1117  void MainWindow::on_action_add_sample() Line 1321  void MainWindow::on_action_add_sample()
1321          }          }
1322          // 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
1323          if (error_files.size()) {          if (error_files.size()) {
1324              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;
1325              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1326              msg.run();              msg.run();
1327          }          }
# Line 1143  void MainWindow::on_action_remove_sample Line 1347  void MainWindow::on_action_remove_sample
1347                       pSample; pSample = group->GetNextSample()) {                       pSample; pSample = group->GetNextSample()) {
1348                      members.push_back(pSample);                      members.push_back(pSample);
1349                  }                  }
1350                    // notify everybody that we're going to remove these samples
1351                    samples_to_be_removed_signal.emit(members);
1352                  // delete the group in the .gig file including the                  // delete the group in the .gig file including the
1353                  // samples that belong to the group                  // samples that belong to the group
1354                  file->DeleteGroup(group);                  file->DeleteGroup(group);
1355                    // notify that we're done with removal
1356                    samples_removed_signal.emit();
1357                  // if sample(s) were just previously added, remove                  // if sample(s) were just previously added, remove
1358                  // them from the import queue                  // them from the import queue
1359                  for (std::list<gig::Sample*>::iterator member = members.begin();                  for (std::list<gig::Sample*>::iterator member = members.begin();
# Line 1162  void MainWindow::on_action_remove_sample Line 1370  void MainWindow::on_action_remove_sample
1370                  }                  }
1371                  file_changed();                  file_changed();
1372              } else if (sample) {              } else if (sample) {
1373                    // notify everybody that we're going to remove this sample
1374                    std::list<gig::Sample*> lsamples;
1375                    lsamples.push_back(sample);
1376                    samples_to_be_removed_signal.emit(lsamples);
1377                  // remove sample from the .gig file                  // remove sample from the .gig file
1378                  file->DeleteSample(sample);                  file->DeleteSample(sample);
1379                    // notify that we're done with removal
1380                    samples_removed_signal.emit();
1381                  // if sample was just previously added, remove it from                  // if sample was just previously added, remove it from
1382                  // the import queue                  // the import queue
1383                  for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();                  for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
# Line 1175  void MainWindow::on_action_remove_sample Line 1389  void MainWindow::on_action_remove_sample
1389                          break;                          break;
1390                      }                      }
1391                  }                  }
1392                    dimreg_changed();
1393                  file_changed();                  file_changed();
1394              }              }
1395              // remove respective row(s) from samples tree view              // remove respective row(s) from samples tree view
1396              m_refSamplesTreeModel->erase(it);              m_refSamplesTreeModel->erase(it);
1397          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1398                // pretend we're done with removal (i.e. to avoid dead locks)
1399                samples_removed_signal.emit();
1400                // show error message
1401              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1402              msg.run();              msg.run();
1403          }          }
1404      }      }
1405  }  }
1406    
1407    // For some reason drag_data_get gets called two times for each
1408    // drag'n'drop (at least when target is an Entry). This work-around
1409    // makes sure the code in drag_data_get and drop_drag_data_received is
1410    // only executed once, as drag_begin only gets called once.
1411    void MainWindow::on_sample_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
1412    {
1413        first_call_to_drag_data_get = true;
1414    }
1415    
1416  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>&,
1417                                                    Gtk::SelectionData& selection_data, guint, guint)                                                    Gtk::SelectionData& selection_data, guint, guint)
1418  {  {
1419        if (!first_call_to_drag_data_get) return;
1420        first_call_to_drag_data_get = false;
1421    
1422      // get selected sample      // get selected sample
1423      gig::Sample* sample = NULL;      gig::Sample* sample = NULL;
1424      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
# Line 1206  void MainWindow::on_sample_label_drop_dr Line 1436  void MainWindow::on_sample_label_drop_dr
1436      const Glib::RefPtr<Gdk::DragContext>& context, int, int,      const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1437      const Gtk::SelectionData& selection_data, guint, guint time)      const Gtk::SelectionData& selection_data, guint, guint time)
1438  {  {
     gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();  
1439      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1440    
1441      if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {      if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
1442          if (sample != dimregion->pSample) {          std::cout << "Drop received sample \"" <<
1443              dimregion->pSample = sample;              sample->pInfo->Name << "\"" << std::endl;
1444              dimreg_edit.wSample->set_text(dimregion->pSample->pInfo->Name.c_str());          // drop success
1445              std::cout << "Drop received sample \"" <<          context->drop_reply(true, time);
1446                  dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;  
1447              // drop success          //TODO: we should better move most of the following code to DimRegionEdit::set_sample()
1448              context->drop_reply(true, time);  
1449              file_changed();          // notify everybody that we're going to alter the region
1450              return;          gig::Region* region = m_RegionChooser.get_region();
1451            region_to_be_changed_signal.emit(region);
1452    
1453            // find the samplechannel dimension
1454            gig::dimension_def_t* stereo_dimension = 0;
1455            for (int i = 0 ; i < region->Dimensions ; i++) {
1456                if (region->pDimensionDefinitions[i].dimension ==
1457                    gig::dimension_samplechannel) {
1458                    stereo_dimension = &region->pDimensionDefinitions[i];
1459                    break;
1460                }
1461            }
1462            bool channels_changed = false;
1463            if (sample->Channels == 1 && stereo_dimension) {
1464                // remove the samplechannel dimension
1465                region->DeleteDimension(stereo_dimension);
1466                channels_changed = true;
1467                region_changed();
1468          }          }
1469            dimreg_edit.set_sample(sample);
1470    
1471            if (sample->Channels == 2 && !stereo_dimension) {
1472                // add samplechannel dimension
1473                gig::dimension_def_t dim;
1474                dim.dimension = gig::dimension_samplechannel;
1475                dim.bits = 1;
1476                dim.zones = 2;
1477                region->AddDimension(&dim);
1478                channels_changed = true;
1479                region_changed();
1480            }
1481            if (channels_changed) {
1482                // unmap all samples with wrong number of channels
1483                // TODO: maybe there should be a warning dialog for this
1484                for (int i = 0 ; i < region->DimensionRegions ; i++) {
1485                    gig::DimensionRegion* d = region->pDimensionRegions[i];
1486                    if (d->pSample && d->pSample->Channels != sample->Channels) {
1487                        gig::Sample* oldref = d->pSample;
1488                        d->pSample = NULL;
1489                        sample_ref_changed_signal.emit(oldref, NULL);
1490                    }
1491                }
1492            }
1493    
1494            // notify we're done with altering
1495            region_changed_signal.emit(region);
1496    
1497            return;
1498      }      }
1499      // drop failed      // drop failed
1500      context->drop_reply(false, time);      context->drop_reply(false, time);
# Line 1258  void MainWindow::instrument_name_changed Line 1533  void MainWindow::instrument_name_changed
1533          file_changed();          file_changed();
1534      }      }
1535  }  }
1536    
1537    void MainWindow::set_file_is_shared(bool b) {
1538        this->file_is_shared = b;
1539    
1540        if (file_is_shared) {
1541            m_AttachedStateLabel.set_label(_("live-mode"));
1542            m_AttachedStateImage.set(
1543                Gdk::Pixbuf::create_from_xpm_data(status_attached_xpm)
1544            );
1545        } else {
1546            m_AttachedStateLabel.set_label(_("stand-alone"));
1547            m_AttachedStateImage.set(
1548                Gdk::Pixbuf::create_from_xpm_data(status_detached_xpm)
1549            );
1550        }
1551    }
1552    
1553    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {
1554        return file_structure_to_be_changed_signal;
1555    }
1556    
1557    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_changed() {
1558        return file_structure_changed_signal;
1559    }
1560    
1561    sigc::signal<void, std::list<gig::Sample*> >& MainWindow::signal_samples_to_be_removed() {
1562        return samples_to_be_removed_signal;
1563    }
1564    
1565    sigc::signal<void>& MainWindow::signal_samples_removed() {
1566        return samples_removed_signal;
1567    }
1568    
1569    sigc::signal<void, gig::Region*>& MainWindow::signal_region_to_be_changed() {
1570        return region_to_be_changed_signal;
1571    }
1572    
1573    sigc::signal<void, gig::Region*>& MainWindow::signal_region_changed() {
1574        return region_changed_signal;
1575    }
1576    
1577    sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& MainWindow::signal_sample_ref_changed() {
1578        return sample_ref_changed_signal;
1579    }
1580    
1581    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_to_be_changed() {
1582        return dimreg_to_be_changed_signal;
1583    }
1584    
1585    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_changed() {
1586        return dimreg_changed_signal;
1587    }

Legend:
Removed from v.1261  
changed lines
  Added in v.1415

  ViewVC Help
Powered by ViewVC