/[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 1679 by schoenebeck, Tue Feb 12 14:13:46 2008 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006, 2007 Andreas Persson   * Copyright (C) 2006 - 2008 Andreas Persson
3   *   *
4   * This program is free software; you can redistribute it and/or   * This program is free software; you can redistribute it and/or
5   * modify it under the terms of the GNU General Public License as   * modify it under the terms of the GNU General Public License as
# 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 150  MainWindow::MainWindow() Line 208  MainWindow::MainWindow()
208          Gtk::Action::create("RemoveSample", Gtk::Stock::REMOVE),          Gtk::Action::create("RemoveSample", Gtk::Stock::REMOVE),
209          sigc::mem_fun(*this, &MainWindow::on_action_remove_sample)          sigc::mem_fun(*this, &MainWindow::on_action_remove_sample)
210      );      );
211        actionGroup->add(
212            Gtk::Action::create("ReplaceAllSamplesInAllGroups", _("Replace All Samples In All Groups")),
213            sigc::mem_fun(*this, &MainWindow::on_action_replace_all_samples_in_all_groups)
214        );
215    
216      uiManager = Gtk::UIManager::create();      uiManager = Gtk::UIManager::create();
217      uiManager->insert_action_group(actionGroup);      uiManager->insert_action_group(actionGroup);
218      // add_accel_group(uiManager->get_accel_group());      add_accel_group(uiManager->get_accel_group());
219    
220      Glib::ustring ui_info =      Glib::ustring ui_info =
221          "<ui>"          "<ui>"
# Line 171  MainWindow::MainWindow() Line 233  MainWindow::MainWindow()
233          "    </menu>"          "    </menu>"
234          "    <menu action='MenuInstrument'>"          "    <menu action='MenuInstrument'>"
235          "    </menu>"          "    </menu>"
236            "    <menu action='MenuView'>"
237            "      <menuitem action='Statusbar'/>"
238            "    </menu>"
239  #ifdef ABOUT_DIALOG  #ifdef ABOUT_DIALOG
240          "    <menu action='MenuHelp'>"          "    <menu action='MenuHelp'>"
241          "      <menuitem action='About'/>"          "      <menuitem action='About'/>"
# Line 187  MainWindow::MainWindow() Line 252  MainWindow::MainWindow()
252          "    <menuitem action='SampleProperties'/>"          "    <menuitem action='SampleProperties'/>"
253          "    <menuitem action='AddGroup'/>"          "    <menuitem action='AddGroup'/>"
254          "    <menuitem action='AddSample'/>"          "    <menuitem action='AddSample'/>"
255            "    <menuitem action='ReplaceAllSamplesInAllGroups' />"
256          "    <separator/>"          "    <separator/>"
257          "    <menuitem action='RemoveSample'/>"          "    <menuitem action='RemoveSample'/>"
258          "  </popup>"          "  </popup>"
# Line 199  MainWindow::MainWindow() Line 265  MainWindow::MainWindow()
265      m_VBox.pack_start(*menuBar, Gtk::PACK_SHRINK);      m_VBox.pack_start(*menuBar, Gtk::PACK_SHRINK);
266      m_VBox.pack_start(m_HPaned);      m_VBox.pack_start(m_HPaned);
267      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
268        m_VBox.pack_start(m_RegionChooser.m_VirtKeybPropsBox, Gtk::PACK_SHRINK);
269      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
270        m_VBox.pack_start(m_StatusBar, Gtk::PACK_SHRINK);
271    
272        // Status Bar:
273        m_StatusBar.pack_start(m_AttachedStateLabel, Gtk::PACK_SHRINK);
274        m_StatusBar.pack_start(m_AttachedStateImage, Gtk::PACK_SHRINK);
275        m_StatusBar.show();
276    
277      m_RegionChooser.signal_sel_changed().connect(      m_RegionChooser.signal_region_selected().connect(
278          sigc::mem_fun(*this, &MainWindow::region_changed) );          sigc::mem_fun(*this, &MainWindow::region_changed) );
279      m_DimRegionChooser.signal_sel_changed().connect(      m_DimRegionChooser.signal_dimregion_selected().connect(
280          sigc::mem_fun(*this, &MainWindow::dimreg_changed) );          sigc::mem_fun(*this, &MainWindow::dimreg_changed) );
281    
282    
# Line 235  MainWindow::MainWindow() Line 308  MainWindow::MainWindow()
308      std::list<Gtk::TargetEntry> drag_target_gig_sample;      std::list<Gtk::TargetEntry> drag_target_gig_sample;
309      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
310      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
311        m_TreeViewSamples.signal_drag_begin().connect(
312            sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)
313        );
314      m_TreeViewSamples.signal_drag_data_get().connect(      m_TreeViewSamples.signal_drag_data_get().connect(
315          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
316      );      );
# Line 242  MainWindow::MainWindow() Line 318  MainWindow::MainWindow()
318      dimreg_edit.wSample->signal_drag_data_received().connect(      dimreg_edit.wSample->signal_drag_data_received().connect(
319          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
320      );      );
321        dimreg_edit.signal_dimreg_changed().connect(
322            sigc::hide(sigc::mem_fun(*this, &MainWindow::file_changed)));
323        m_RegionChooser.signal_instrument_changed().connect(
324            sigc::mem_fun(*this, &MainWindow::file_changed));
325        m_DimRegionChooser.signal_region_changed().connect(
326            sigc::mem_fun(*this, &MainWindow::file_changed));
327        instrumentProps.signal_instrument_changed().connect(
328            sigc::mem_fun(*this, &MainWindow::file_changed));
329        propDialog.signal_info_changed().connect(
330            sigc::mem_fun(*this, &MainWindow::file_changed));
331    
332        dimreg_edit.signal_dimreg_to_be_changed().connect(
333            dimreg_to_be_changed_signal.make_slot());
334        dimreg_edit.signal_dimreg_changed().connect(
335            dimreg_changed_signal.make_slot());
336        dimreg_edit.signal_sample_ref_changed().connect(
337            sample_ref_changed_signal.make_slot());
338    
339        m_RegionChooser.signal_instrument_struct_to_be_changed().connect(
340            sigc::hide(
341                sigc::bind(
342                    file_structure_to_be_changed_signal.make_slot(),
343                    sigc::ref(this->file)
344                )
345            )
346        );
347        m_RegionChooser.signal_instrument_struct_changed().connect(
348            sigc::hide(
349                sigc::bind(
350                    file_structure_changed_signal.make_slot(),
351                    sigc::ref(this->file)
352                )
353            )
354        );
355        m_RegionChooser.signal_region_to_be_changed().connect(
356            region_to_be_changed_signal.make_slot());
357        m_RegionChooser.signal_region_changed_signal().connect(
358            region_changed_signal.make_slot());
359    
360        note_on_signal.connect(
361            sigc::mem_fun(m_RegionChooser, &RegionChooser::on_note_on_event));
362        note_off_signal.connect(
363            sigc::mem_fun(m_RegionChooser, &RegionChooser::on_note_off_event));
364    
365        dimreg_all_regions.signal_toggled().connect(
366            sigc::mem_fun(*this, &MainWindow::update_dimregs));
367        dimreg_all_dimregs.signal_toggled().connect(
368            sigc::mem_fun(*this, &MainWindow::dimreg_all_dimregs_toggled));
369        dimreg_stereo.signal_toggled().connect(
370            sigc::mem_fun(*this, &MainWindow::update_dimregs));
371    
372      file = 0;      file = 0;
373        file_is_changed = false;
374        set_file_is_shared(false);
375    
376      show_all_children();      show_all_children();
377    
378        // start with a new gig file by default
379        on_action_file_new();
380  }  }
381    
382  MainWindow::~MainWindow()  MainWindow::~MainWindow()
383  {  {
384  }  }
385    
386  void MainWindow::region_changed()  bool MainWindow::on_delete_event(GdkEventAny* event)
387  {  {
388      m_DimRegionChooser.set_region(m_RegionChooser.get_region());      return !file_is_shared && file_is_changed && !close_confirmation_dialog();
389  }  }
390    
391  void MainWindow::dimreg_changed()  void MainWindow::on_action_quit()
392  {  {
393      dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
394        hide();
395  }  }
396    
397  void MainWindow::on_sel_change()  void MainWindow::region_changed()
398    {
399        m_DimRegionChooser.set_region(m_RegionChooser.get_region());
400    }
401    
402    gig::Instrument* MainWindow::get_instrument()
403  {  {
404        gig::Instrument* instrument = 0;
405      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
406    
407      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
408      if (it) {      if (it) {
409          Gtk::TreeModel::Row row = *it;          Gtk::TreeModel::Row row = *it;
410          std::cout << row[m_Columns.m_col_name] << std::endl;          instrument = row[m_Columns.m_col_instr];
411        }
412        return instrument;
413    }
414    
415          m_RegionChooser.set_instrument(row[m_Columns.m_col_instr]);  void MainWindow::add_region_to_dimregs(gig::Region* region, bool stereo, bool all_dimregs)
416    {
417        if (all_dimregs) {
418            for (int i = 0 ; i < region->DimensionRegions ; i++) {
419                if (region->pDimensionRegions[i]) {
420                    dimreg_edit.dimregs.insert(region->pDimensionRegions[i]);
421                }
422            }
423      } else {      } else {
424          m_RegionChooser.set_instrument(0);          m_DimRegionChooser.get_dimregions(region, stereo, dimreg_edit.dimregs);
425        }
426    }
427    
428    void MainWindow::update_dimregs()
429    {
430        dimreg_edit.dimregs.clear();
431        bool all_regions = dimreg_all_regions.get_active();
432        bool stereo = dimreg_stereo.get_active();
433        bool all_dimregs = dimreg_all_dimregs.get_active();
434    
435        if (all_regions) {
436            gig::Instrument* instrument = get_instrument();
437            if (instrument) {
438                for (gig::Region* region = instrument->GetFirstRegion() ;
439                     region ;
440                     region = instrument->GetNextRegion()) {
441                    add_region_to_dimregs(region, stereo, all_dimregs);
442                }
443            }
444        } else {
445            gig::Region* region = m_RegionChooser.get_region();
446            if (region) {
447                add_region_to_dimregs(region, stereo, all_dimregs);
448            }
449      }      }
450  }  }
451    
452    void MainWindow::dimreg_all_dimregs_toggled()
453    {
454        dimreg_stereo.set_sensitive(!dimreg_all_dimregs.get_active());
455        update_dimregs();
456    }
457    
458    void MainWindow::dimreg_changed()
459    {
460        update_dimregs();
461        dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());
462    }
463    
464    void MainWindow::on_sel_change()
465    {
466        m_RegionChooser.set_instrument(get_instrument());
467    }
468    
469  void loader_progress_callback(gig::progress_t* progress)  void loader_progress_callback(gig::progress_t* progress)
470  {  {
471      Loader* loader = static_cast<Loader*>(progress->custom);      Loader* loader = static_cast<Loader*>(progress->custom);
# Line 362  void MainWindow::__clear() { Line 551  void MainWindow::__clear() {
551      m_refTreeModel->clear();      m_refTreeModel->clear();
552      m_refSamplesTreeModel->clear();      m_refSamplesTreeModel->clear();
553      // free libgig's gig::File instance      // free libgig's gig::File instance
554      if (file) {      if (file && !file_is_shared) delete file;
555          delete file;      file = NULL;
556          file = NULL;      set_file_is_shared(false);
     }  
557  }  }
558    
559  void MainWindow::on_action_file_new()  void MainWindow::on_action_file_new()
560  {  {
561        if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
562    
563        if (file_is_shared && !leaving_shared_mode_dialog()) return;
564    
565      // clear all GUI elements      // clear all GUI elements
566      __clear();      __clear();
567      // create a new .gig file (virtually yet)      // create a new .gig file (virtually yet)
# Line 378  void MainWindow::on_action_file_new() Line 570  void MainWindow::on_action_file_new()
570      gig::Instrument* pInstrument = pFile->AddInstrument();      gig::Instrument* pInstrument = pFile->AddInstrument();
571      pInstrument->pInfo->Name = "Unnamed Instrument";      pInstrument->pInfo->Name = "Unnamed Instrument";
572      // update GUI with that new gig::File      // update GUI with that new gig::File
573      load_gig(pFile, NULL /*no file name yet*/);      load_gig(pFile, 0 /*no file name yet*/);
574    }
575    
576    bool MainWindow::close_confirmation_dialog()
577    {
578        gchar* msg = g_strdup_printf(_("Save changes to \"%s\" before closing?"),
579                                     Glib::filename_display_basename(filename).c_str());
580        Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
581        g_free(msg);
582    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
583        dialog.set_secondary_text(_("If you close without saving, your changes will be lost."));
584    #endif
585        dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
586        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
587        dialog.add_button(file_has_name ? Gtk::Stock::SAVE : Gtk::Stock::SAVE_AS, Gtk::RESPONSE_YES);
588        dialog.set_default_response(Gtk::RESPONSE_YES);
589        int response = dialog.run();
590        dialog.hide();
591        if (response == Gtk::RESPONSE_YES) return file_save();
592        return response != Gtk::RESPONSE_CANCEL;
593    }
594    
595    bool MainWindow::leaving_shared_mode_dialog() {
596        Glib::ustring msg = _("Detach from sampler and proceed working stand-alone?");
597        Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
598    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
599        dialog.set_secondary_text(
600            _("If you proceed to work on another instrument file, it won't be "
601              "used by the sampler until you tell the sampler explicitly to "
602              "load it.")
603       );
604    #endif
605        dialog.add_button(_("_Yes, Detach"), Gtk::RESPONSE_YES);
606        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
607        dialog.set_default_response(Gtk::RESPONSE_CANCEL);
608        int response = dialog.run();
609        dialog.hide();
610        return response == Gtk::RESPONSE_YES;
611  }  }
612    
613  void MainWindow::on_action_file_open()  void MainWindow::on_action_file_open()
614  {  {
615        if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
616    
617        if (file_is_shared && !leaving_shared_mode_dialog()) return;
618    
619      Gtk::FileChooserDialog dialog(*this, _("Open file"));      Gtk::FileChooserDialog dialog(*this, _("Open file"));
620      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
621      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
622        dialog.set_default_response(Gtk::RESPONSE_OK);
623      Gtk::FileFilter filter;      Gtk::FileFilter filter;
624      filter.add_pattern("*.gig");      filter.add_pattern("*.gig");
625      dialog.set_filter(filter);      dialog.set_filter(filter);
626        if (current_dir != "") {
627            dialog.set_current_folder(current_dir);
628        }
629      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
630          printf("filename=%s\n", dialog.get_filename().c_str());          std::string filename = dialog.get_filename();
631          __clear();          printf("filename=%s\n", filename.c_str());
632          printf("on_action_file_open self=%x\n", Glib::Thread::self());          printf("on_action_file_open self=%x\n", Glib::Thread::self());
633          load_file(dialog.get_filename().c_str());          load_file(filename.c_str());
634            current_dir = Glib::path_get_dirname(filename);
635      }      }
636  }  }
637    
638  void MainWindow::load_file(const char* name)  void MainWindow::load_file(const char* name)
639  {  {
640        __clear();
641      load_dialog = new LoadDialog("Loading...", *this);      load_dialog = new LoadDialog("Loading...", *this);
642      load_dialog->show_all();      load_dialog->show_all();
643      loader = new Loader(strdup(name));      loader = new Loader(strdup(name));
# Line 416  void MainWindow::load_instrument(gig::In Line 655  void MainWindow::load_instrument(gig::In
655          msg.run();          msg.run();
656          Gtk::Main::quit();          Gtk::Main::quit();
657      }      }
658        // clear all GUI elements
659        __clear();
660        // load the instrument
661      gig::File* pFile = (gig::File*) instr->GetParent();      gig::File* pFile = (gig::File*) instr->GetParent();
662      load_gig(pFile, NULL /*file name*/);      load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);
663      //TODO: automatically select the given instrument      //TODO: automatically select the given instrument
664  }  }
665    
# Line 436  void MainWindow::on_loader_finished() Line 678  void MainWindow::on_loader_finished()
678    
679  void MainWindow::on_action_file_save()  void MainWindow::on_action_file_save()
680  {  {
681      if (!file) return;      file_save();
682    }
683    
684    bool MainWindow::check_if_savable()
685    {
686        if (!file) return false;
687    
688        if (!file->GetFirstSample()) {
689            Gtk::MessageDialog(*this, _("The file could not be saved "
690                                        "because it contains no samples"),
691                               false, Gtk::MESSAGE_ERROR).run();
692            return false;
693        }
694    
695        for (gig::Instrument* instrument = file->GetFirstInstrument() ; instrument ;
696             instrument = file->GetNextInstrument()) {
697            if (!instrument->GetFirstRegion()) {
698                Gtk::MessageDialog(*this, _("The file could not be saved "
699                                            "because there are instruments "
700                                            "that have no regions"),
701                                   false, Gtk::MESSAGE_ERROR).run();
702                return false;
703            }
704        }
705        return true;
706    }
707    
708    bool MainWindow::file_save()
709    {
710        if (!check_if_savable()) return false;
711        if (!file_is_shared && !file_has_name) return file_save_as();
712    
713      std::cout << "Saving file\n" << std::flush;      std::cout << "Saving file\n" << std::flush;
714        file_structure_to_be_changed_signal.emit(this->file);
715      try {      try {
716          file->Save();          file->Save();
717            if (file_is_changed) {
718                set_title(get_title().substr(1));
719                file_is_changed = false;
720            }
721      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
722          Glib::ustring txt = "Could not save file: " + e.Message;          file_structure_changed_signal.emit(this->file);
723            Glib::ustring txt = _("Could not save file: ") + e.Message;
724          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
725          msg.run();          msg.run();
726          return;          return false;
727      }      }
728      std::cout << "Saving file done\n" << std::flush;      std::cout << "Saving file done\n" << std::flush;
729      __import_queued_samples();      __import_queued_samples();
730        file_structure_changed_signal.emit(this->file);
731        return true;
732  }  }
733    
734  void MainWindow::on_action_file_save_as()  void MainWindow::on_action_file_save_as()
735  {  {
736      if (!file) return;      if (!check_if_savable()) return;
737      Gtk::FileChooserDialog dialog(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SAVE);      file_save_as();
738    }
739    
740    bool MainWindow::file_save_as()
741    {
742        Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);
743      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
744      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
745        dialog.set_default_response(Gtk::RESPONSE_OK);
746    
747    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 8) || GTKMM_MAJOR_VERSION > 2
748        dialog.set_do_overwrite_confirmation();
749        // TODO: an overwrite dialog for gtkmm < 2.8
750    #endif
751      Gtk::FileFilter filter;      Gtk::FileFilter filter;
752      filter.add_pattern("*.gig");      filter.add_pattern("*.gig");
753      dialog.set_filter(filter);      dialog.set_filter(filter);
754    
755        // set initial dir and filename of the Save As dialog
756        // and prepare that initial filename as a copy of the gig
757        {
758            std::string basename = Glib::path_get_basename(filename);
759            std::string dir = Glib::path_get_dirname(filename);
760            basename = std::string("copy_of_") + basename;
761            Glib::ustring copyFileName = Glib::build_filename(dir, basename);
762            if (Glib::path_is_absolute(filename)) {
763                dialog.set_filename(copyFileName);
764            } else {
765                if (current_dir != "") dialog.set_current_folder(current_dir);
766            }
767            dialog.set_current_name(Glib::filename_display_basename(copyFileName));
768        }
769    
770        // show warning in the dialog
771        Gtk::HBox descriptionArea;
772        descriptionArea.set_spacing(15);
773        Gtk::Image warningIcon(Gtk::Stock::DIALOG_WARNING, Gtk::IconSize(Gtk::ICON_SIZE_DIALOG));
774        descriptionArea.pack_start(warningIcon, Gtk::PACK_SHRINK);
775        warningIcon.show();
776        Gtk::Label description;
777        description.set_markup(
778            _("\n<b>CAUTION:</b> You <b>MUST</b> use the "
779              "<span style=\"italic\">\"Save\"</span> dialog instead of "
780              "<span style=\"italic\">\"Save As...\"</span> if you want to save "
781              "to the same .gig file. Using "
782              "<span style=\"italic\">\"Save As...\"</span> for writing to the "
783              "same .gig file will end up in corrupted sample wave data!\n")
784        );
785        description.set_line_wrap(true);
786        descriptionArea.pack_start(description, Gtk::PACK_SHRINK);
787        description.show();
788        dialog.get_vbox()->pack_start(descriptionArea, Gtk::PACK_SHRINK);
789        descriptionArea.show();
790    
791      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
792          printf("filename=%s\n", dialog.get_filename().c_str());          file_structure_to_be_changed_signal.emit(this->file);
793          try {          try {
794              file->Save(dialog.get_filename());              std::string filename = dialog.get_filename();
795                if (!Glib::str_has_suffix(filename, ".gig")) {
796                    filename += ".gig";
797                }
798                printf("filename=%s\n", filename.c_str());
799                file->Save(filename);
800                this->filename = filename;
801                current_dir = Glib::path_get_dirname(filename);
802                set_title(Glib::filename_display_basename(filename));
803                file_has_name = true;
804                file_is_changed = false;
805          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
806              Glib::ustring txt = "Could not save file: " + e.Message;              file_structure_changed_signal.emit(this->file);
807                Glib::ustring txt = _("Could not save file: ") + e.Message;
808              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
809              msg.run();              msg.run();
810              return;              return false;
811          }          }
812          __import_queued_samples();          __import_queued_samples();
813            file_structure_changed_signal.emit(this->file);
814            return true;
815      }      }
816        return false;
817  }  }
818    
819  // 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 833  void MainWindow::__import_queued_samples
833              int bitdepth;              int bitdepth;
834              switch (info.format & 0xff) {              switch (info.format & 0xff) {
835                  case SF_FORMAT_PCM_S8:                  case SF_FORMAT_PCM_S8:
                     bitdepth = 16; // we simply convert to 16 bit for now  
                     break;  
836                  case SF_FORMAT_PCM_16:                  case SF_FORMAT_PCM_16:
837                    case SF_FORMAT_PCM_U8:
838                      bitdepth = 16;                      bitdepth = 16;
839                      break;                      break;
840                  case SF_FORMAT_PCM_24:                  case SF_FORMAT_PCM_24:
                     bitdepth = 32; // we simply convert to 32 bit for now  
                     break;  
841                  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;  
842                  case SF_FORMAT_FLOAT:                  case SF_FORMAT_FLOAT:
                     bitdepth = 32;  
                     break;  
843                  case SF_FORMAT_DOUBLE:                  case SF_FORMAT_DOUBLE:
844                      bitdepth = 32; // I guess we will always truncate this to 32 bit                      bitdepth = 24;
845                      break;                      break;
846                  default:                  default:
847                      sf_close(hFile); // close sound file                      sf_close(hFile); // close sound file
848                      throw std::string("format not supported"); // unsupported subformat (yet?)                      throw std::string("format not supported"); // unsupported subformat (yet?)
849              }              }
850              // allocate appropriate copy buffer (TODO: for now we copy  
851              // 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;  
852              switch (bitdepth) {              switch (bitdepth) {
853                  case 16:                  case 16: {
854                      buffer = new int8_t[2 * info.channels * info.frames];                      short* buffer = new short[bufsize * info.channels];
855                      // libsndfile does the conversion for us (if needed)                      sf_count_t cnt = info.frames;
856                      sf_readf_short(hFile, (short*) buffer, info.frames);                      while (cnt) {
857                            // libsndfile does the conversion for us (if needed)
858                            int n = sf_readf_short(hFile, buffer, bufsize);
859                            // write from buffer directly (physically) into .gig file
860                            iter->gig_sample->Write(buffer, n);
861                            cnt -= n;
862                        }
863                        delete[] buffer;
864                      break;                      break;
865                  case 32:                  }
866                      buffer = new int8_t[4 * info.channels * info.frames];                  case 24: {
867                      // libsndfile does the conversion for us (if needed)                      int* srcbuf = new int[bufsize * info.channels];
868                      sf_readf_int(hFile, (int*) buffer, info.frames);                      uint8_t* dstbuf = new uint8_t[bufsize * 3 * info.channels];
869                        sf_count_t cnt = info.frames;
870                        while (cnt) {
871                            // libsndfile returns 32 bits, convert to 24
872                            int n = sf_readf_int(hFile, srcbuf, bufsize);
873                            int j = 0;
874                            for (int i = 0 ; i < n * info.channels ; i++) {
875                                dstbuf[j++] = srcbuf[i] >> 8;
876                                dstbuf[j++] = srcbuf[i] >> 16;
877                                dstbuf[j++] = srcbuf[i] >> 24;
878                            }
879                            // write from buffer directly (physically) into .gig file
880                            iter->gig_sample->Write(dstbuf, n);
881                            cnt -= n;
882                        }
883                        delete[] srcbuf;
884                        delete[] dstbuf;
885                      break;                      break;
886                    }
887              }              }
             // write from buffer directly (physically) into .gig file  
             (*iter).gig_sample->Write(buffer, info.frames);  
888              // cleanup              // cleanup
889              sf_close(hFile);              sf_close(hFile);
             delete[] buffer;  
890              // on success we remove the sample from the import queue,              // on success we remove the sample from the import queue,
891              // otherwise keep it, maybe it works the next time ?              // otherwise keep it, maybe it works the next time ?
892              std::list<SampleImportItem>::iterator cur = iter;              std::list<SampleImportItem>::iterator cur = iter;
# Line 549  void MainWindow::__import_queued_samples Line 901  void MainWindow::__import_queued_samples
901      }      }
902      // show error message box when some sample(s) could not be imported      // show error message box when some sample(s) could not be imported
903      if (error_files.size()) {      if (error_files.size()) {
904          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;
905          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
906          msg.run();          msg.run();
907      }      }
# Line 566  void MainWindow::on_action_help_about() Line 918  void MainWindow::on_action_help_about()
918  #ifdef ABOUT_DIALOG  #ifdef ABOUT_DIALOG
919      Gtk::AboutDialog dialog;      Gtk::AboutDialog dialog;
920      dialog.set_version(VERSION);      dialog.set_version(VERSION);
921        dialog.set_copyright("Copyright (C) 2006,2007 Andreas Persson");
922        dialog.set_comments(
923            "Released under the GNU General Public License.\n"
924            "\n"
925            "Please notice that this is still a very young instrument editor. "
926            "So better backup your Gigasampler files before editing them with "
927            "this application.\n"
928            "\n"
929            "Please report bugs to: http://bugs.linuxsampler.org"
930        );
931        dialog.set_website("http://www.linuxsampler.org");
932        dialog.set_website_label("http://www.linuxsampler.org");
933      dialog.run();      dialog.run();
934  #endif  #endif
935  }  }
936    
937  PropDialog::PropDialog()  PropDialog::PropDialog()
938      : table(2,1)      : table(2,1),
939          eName("Name"),
940          eCreationDate("Creation date"),
941          eComments("Comments"),
942          eProduct("Product"),
943          eCopyright("Copyright"),
944          eArtists("Artists"),
945          eGenre("Genre"),
946          eKeywords("Keywords"),
947          eEngineer("Engineer"),
948          eTechnician("Technician"),
949          eSoftware("Software"),
950          eMedium("Medium"),
951          eSource("Source"),
952          eSourceForm("Source form"),
953          eCommissioned("Commissioned"),
954          eSubject("Subject"),
955          quitButton(Gtk::Stock::CLOSE),
956          update_model(0)
957  {  {
958        set_title("File Properties");
959        eName.set_width_chars(50);
960    
961        connect(eName, &DLS::Info::Name);
962        connect(eCreationDate, &DLS::Info::CreationDate);
963        connect(eComments, &DLS::Info::Comments);
964        connect(eProduct, &DLS::Info::Product);
965        connect(eCopyright, &DLS::Info::Copyright);
966        connect(eArtists, &DLS::Info::Artists);
967        connect(eGenre, &DLS::Info::Genre);
968        connect(eKeywords, &DLS::Info::Keywords);
969        connect(eEngineer, &DLS::Info::Engineer);
970        connect(eTechnician, &DLS::Info::Technician);
971        connect(eSoftware, &DLS::Info::Software);
972        connect(eMedium, &DLS::Info::Medium);
973        connect(eSource, &DLS::Info::Source);
974        connect(eSourceForm, &DLS::Info::SourceForm);
975        connect(eCommissioned, &DLS::Info::Commissioned);
976        connect(eSubject, &DLS::Info::Subject);
977    
978        table.add(eName);
979        table.add(eCreationDate);
980        table.add(eComments);
981        table.add(eProduct);
982        table.add(eCopyright);
983        table.add(eArtists);
984        table.add(eGenre);
985        table.add(eKeywords);
986        table.add(eEngineer);
987        table.add(eTechnician);
988        table.add(eSoftware);
989        table.add(eMedium);
990        table.add(eSource);
991        table.add(eSourceForm);
992        table.add(eCommissioned);
993        table.add(eSubject);
994    
995      table.set_col_spacings(5);      table.set_col_spacings(5);
996      const char* propLabels[] = {      add(vbox);
997          "Name:",      table.set_border_width(5);
998          "CreationDate:",      vbox.add(table);
999          "Comments:", // TODO: multiline      vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
1000          "Product:",      buttonBox.set_layout(Gtk::BUTTONBOX_END);
1001          "Copyright:",      buttonBox.set_border_width(5);
1002          "Artists:",      buttonBox.show();
1003          "Genre:",      buttonBox.pack_start(quitButton);
1004          "Keywords:",      quitButton.set_flags(Gtk::CAN_DEFAULT);
1005          "Engineer:",      quitButton.grab_focus();
1006          "Technician:",      quitButton.signal_clicked().connect(
1007          "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);  
     }  
1008    
1009      add(table);      quitButton.show();
1010      // add_button(Gtk::Stock::CANCEL, 0);      vbox.show();
     // add_button(Gtk::Stock::OK, 1);  
1011      show_all_children();      show_all_children();
1012  }  }
1013    
1014  void PropDialog::set_info(DLS::Info* info)  void PropDialog::set_info(DLS::Info* info)
1015  {  {
1016      entry[0].set_text(info->Name);      this->info = info;
1017      entry[1].set_text(info->CreationDate);      update_model++;
1018      entry[2].set_text(Glib::convert(info->Comments, "UTF-8", "ISO-8859-1"));      eName.set_value(info->Name);
1019      entry[3].set_text(info->Product);      eCreationDate.set_value(info->CreationDate);
1020      entry[4].set_text(info->Copyright);      eComments.set_value(info->Comments);
1021      entry[5].set_text(info->Artists);      eProduct.set_value(info->Product);
1022      entry[6].set_text(info->Genre);      eCopyright.set_value(info->Copyright);
1023      entry[7].set_text(info->Keywords);      eArtists.set_value(info->Artists);
1024      entry[8].set_text(info->Engineer);      eGenre.set_value(info->Genre);
1025      entry[9].set_text(info->Technician);      eKeywords.set_value(info->Keywords);
1026      entry[10].set_text(info->Software);      eEngineer.set_value(info->Engineer);
1027      entry[11].set_text(info->Medium);      eTechnician.set_value(info->Technician);
1028      entry[12].set_text(info->Source);      eSoftware.set_value(info->Software);
1029      entry[13].set_text(info->SourceForm);      eMedium.set_value(info->Medium);
1030      entry[14].set_text(info->Commissioned);      eSource.set_value(info->Source);
1031      entry[15].set_text(info->Subject);      eSourceForm.set_value(info->SourceForm);
1032  }      eCommissioned.set_value(info->Commissioned);
1033        eSubject.set_value(info->Subject);
1034  void InstrumentProps::add_prop(LabelWidget& prop)      update_model--;
1035  {  }
1036      table.attach(prop.label, 0, 1, rowno, rowno + 1,  
1037                   Gtk::FILL, Gtk::SHRINK);  sigc::signal<void>& PropDialog::signal_info_changed()
1038      table.attach(prop.widget, 1, 2, rowno, rowno + 1,  {
1039                   Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);      return info_changed;
1040      rowno++;  }
1041    
1042    void InstrumentProps::set_IsDrum(bool value)
1043    {
1044        instrument->IsDrum = value;
1045    }
1046    
1047    void InstrumentProps::set_MIDIBank(uint16_t value)
1048    {
1049        instrument->MIDIBank = value;
1050    }
1051    
1052    void InstrumentProps::set_MIDIProgram(uint32_t value)
1053    {
1054        instrument->MIDIProgram = value;
1055    }
1056    
1057    void InstrumentProps::set_DimensionKeyRange_low(uint8_t value)
1058    {
1059        instrument->DimensionKeyRange.low = value;
1060        if (value > instrument->DimensionKeyRange.high) {
1061            eDimensionKeyRangeHigh.set_value(value);
1062        }
1063    }
1064    
1065    void InstrumentProps::set_DimensionKeyRange_high(uint8_t value)
1066    {
1067        instrument->DimensionKeyRange.high = value;
1068        if (value < instrument->DimensionKeyRange.low) {
1069            eDimensionKeyRangeLow.set_value(value);
1070        }
1071  }  }
1072    
1073  InstrumentProps::InstrumentProps()  InstrumentProps::InstrumentProps()
1074      : table(2,1),      : table(2,1),
1075        quitButton(Gtk::Stock::CLOSE),        quitButton(Gtk::Stock::CLOSE),
1076        eName("Name"),        eName("Name"),
1077        eIsDrum("IsDrum"),        eIsDrum("Is drum"),
1078        eMIDIBank("MIDIBank", 0, 16383),        eMIDIBank("MIDI bank", 0, 16383),
1079        eMIDIProgram("MIDIProgram"),        eMIDIProgram("MIDI program"),
1080        eAttenuation("Attenuation", 0, 96, 0, 1),        eAttenuation("Attenuation", 0, 96, 0, 1),
1081        eGainPlus6("Gain +6dB", eAttenuation, -6),        eGainPlus6("Gain +6dB", eAttenuation, -6),
1082        eEffectSend("EffectSend", 0, 65535),        eEffectSend("Effect send", 0, 65535),
1083        eFineTune("FineTune", -8400, 8400),        eFineTune("Fine tune", -8400, 8400),
1084        ePitchbendRange("PitchbendRange", 0, 12),        ePitchbendRange("Pitchbend range", 0, 12),
1085        ePianoReleaseMode("PianoReleaseMode"),        ePianoReleaseMode("Piano release mode"),
1086        eDimensionKeyRangeLow("DimensionKeyRangeLow"),        eDimensionKeyRangeLow("Keyswitching range low"),
1087        eDimensionKeyRangeHigh("DimensionKeyRangeHigh")        eDimensionKeyRangeHigh("Keyswitching range high"),
1088  {        update_model(0)
1089      set_title("Instrument properties");  {
1090        set_title("Instrument Properties");
1091    
1092        eDimensionKeyRangeLow.set_tip(
1093            _("start of the keyboard area which should switch the "
1094              "\"keyswitching\" dimension")
1095        );
1096        eDimensionKeyRangeHigh.set_tip(
1097            _("end of the keyboard area which should switch the "
1098              "\"keyswitching\" dimension")
1099        );
1100    
1101        connect(eIsDrum, &InstrumentProps::set_IsDrum);
1102        connect(eMIDIBank, &InstrumentProps::set_MIDIBank);
1103        connect(eMIDIProgram, &InstrumentProps::set_MIDIProgram);
1104        connect(eAttenuation, &gig::Instrument::Attenuation);
1105        connect(eGainPlus6, &gig::Instrument::Attenuation);
1106        connect(eEffectSend, &gig::Instrument::EffectSend);
1107        connect(eFineTune, &gig::Instrument::FineTune);
1108        connect(ePitchbendRange, &gig::Instrument::PitchbendRange);
1109        connect(ePianoReleaseMode, &gig::Instrument::PianoReleaseMode);
1110        connect(eDimensionKeyRangeLow,
1111                &InstrumentProps::set_DimensionKeyRange_low);
1112        connect(eDimensionKeyRangeHigh,
1113                &InstrumentProps::set_DimensionKeyRange_high);
1114    
     rowno = 0;  
1115      table.set_col_spacings(5);      table.set_col_spacings(5);
1116    
1117      add_prop(eName);      table.add(eName);
1118      add_prop(eIsDrum);      table.add(eIsDrum);
1119      add_prop(eMIDIBank);      table.add(eMIDIBank);
1120      add_prop(eMIDIProgram);      table.add(eMIDIProgram);
1121      add_prop(eAttenuation);      table.add(eAttenuation);
1122      add_prop(eGainPlus6);      table.add(eGainPlus6);
1123      add_prop(eEffectSend);      table.add(eEffectSend);
1124      add_prop(eFineTune);      table.add(eFineTune);
1125      add_prop(ePitchbendRange);      table.add(ePitchbendRange);
1126      add_prop(ePianoReleaseMode);      table.add(ePianoReleaseMode);
1127      add_prop(eDimensionKeyRangeLow);      table.add(eDimensionKeyRangeLow);
1128      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));  
1129    
1130      add(vbox);      add(vbox);
1131      table.set_border_width(5);      table.set_border_width(5);
# Line 696  InstrumentProps::InstrumentProps() Line 1149  InstrumentProps::InstrumentProps()
1149    
1150  void InstrumentProps::set_instrument(gig::Instrument* instrument)  void InstrumentProps::set_instrument(gig::Instrument* instrument)
1151  {  {
1152      update_gui = false;      this->instrument = instrument;
1153      eName.set_ptr(&instrument->pInfo->Name);  
1154      eIsDrum.set_ptr(&instrument->IsDrum);      update_model++;
1155      eMIDIBank.set_ptr(&instrument->MIDIBank);      eName.set_value(instrument->pInfo->Name);
1156      eMIDIProgram.set_ptr(&instrument->MIDIProgram);      eIsDrum.set_value(instrument->IsDrum);
1157      eAttenuation.set_ptr(&instrument->Attenuation);      eMIDIBank.set_value(instrument->MIDIBank);
1158      eGainPlus6.set_ptr(&instrument->Attenuation);      eMIDIProgram.set_value(instrument->MIDIProgram);
1159      eEffectSend.set_ptr(&instrument->EffectSend);      eAttenuation.set_value(instrument->Attenuation);
1160      eFineTune.set_ptr(&instrument->FineTune);      eGainPlus6.set_value(instrument->Attenuation);
1161      ePitchbendRange.set_ptr(&instrument->PitchbendRange);      eEffectSend.set_value(instrument->EffectSend);
1162      ePianoReleaseMode.set_ptr(&instrument->PianoReleaseMode);      eFineTune.set_value(instrument->FineTune);
1163      eDimensionKeyRangeLow.set_ptr(&instrument->DimensionKeyRange.low);      ePitchbendRange.set_value(instrument->PitchbendRange);
1164      eDimensionKeyRangeHigh.set_ptr(&instrument->DimensionKeyRange.high);      ePianoReleaseMode.set_value(instrument->PianoReleaseMode);
1165      update_gui = true;      eDimensionKeyRangeLow.set_value(instrument->DimensionKeyRange.low);
1166        eDimensionKeyRangeHigh.set_value(instrument->DimensionKeyRange.high);
1167        update_model--;
1168  }  }
1169    
1170  void InstrumentProps::key_range_low_changed()  sigc::signal<void>& InstrumentProps::signal_instrument_changed()
1171  {  {
1172      double l = eDimensionKeyRangeLow.get_value();      return instrument_changed;
     double h = eDimensionKeyRangeHigh.get_value();  
     if (h < l) eDimensionKeyRangeHigh.set_value(l);  
1173  }  }
1174    
1175  void InstrumentProps::key_range_high_changed()  void MainWindow::file_changed()
1176  {  {
1177      double l = eDimensionKeyRangeLow.get_value();      if (file && !file_is_changed) {
1178      double h = eDimensionKeyRangeHigh.get_value();          set_title("*" + get_title());
1179      if (h < l) eDimensionKeyRangeLow.set_value(h);          file_is_changed = true;
1180        }
1181  }  }
1182    
1183  void MainWindow::load_gig(gig::File* gig, const char* filename)  void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)
1184  {  {
1185      file = gig;      file = 0;
1186        set_file_is_shared(isSharedInstrument);
1187    
1188      if (filename) {      this->filename = filename ? filename : _("Unsaved Gig File");
1189          const char *basename = strrchr(filename, '/');      set_title(Glib::filename_display_basename(this->filename));
1190          basename = basename ? basename + 1 : filename;      file_has_name = filename;
1191          set_title(basename);      file_is_changed = false;
     } else {  
         set_title("unnamed");  
     }  
1192    
1193      propDialog.set_info(gig->pInfo);      propDialog.set_info(gig->pInfo);
1194    
# Line 785  void MainWindow::load_gig(gig::File* gig Line 1237  void MainWindow::load_gig(gig::File* gig
1237          }          }
1238      }      }
1239    
1240        file = gig;
1241    
1242      // select the first instrument      // select the first instrument
1243      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1244      tree_sel_ref->select(Gtk::TreePath("0"));      tree_sel_ref->select(Gtk::TreePath("0"));
# Line 792  void MainWindow::load_gig(gig::File* gig Line 1246  void MainWindow::load_gig(gig::File* gig
1246    
1247  void MainWindow::show_instr_props()  void MainWindow::show_instr_props()
1248  {  {
1249      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      gig::Instrument* instrument = get_instrument();
1250      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      if (instrument)
     if (it)  
1251      {      {
1252          Gtk::TreeModel::Row row = *it;          instrumentProps.set_instrument(instrument);
1253          if (row[m_Columns.m_col_instr])          instrumentProps.show();
1254          {          instrumentProps.deiconify();
             instrumentProps.set_instrument(row[m_Columns.m_col_instr]);  
             instrumentProps.show();  
             instrumentProps.deiconify();  
         }  
1255      }      }
1256  }  }
1257    
1258    void MainWindow::on_action_view_status_bar() {
1259        Gtk::CheckMenuItem* item =
1260            dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuView/Statusbar"));
1261        if (!item) {
1262            std::cerr << "/MenuBar/MenuView/Statusbar == NULL\n";
1263            return;
1264        }
1265        if (item->get_active()) m_StatusBar.show();
1266        else                    m_StatusBar.hide();
1267    }
1268    
1269  void MainWindow::on_button_release(GdkEventButton* button)  void MainWindow::on_button_release(GdkEventButton* button)
1270  {  {
1271      if (button->type == GDK_2BUTTON_PRESS) {      if (button->type == GDK_2BUTTON_PRESS) {
# Line 858  void MainWindow::on_action_add_instrumen Line 1318  void MainWindow::on_action_add_instrumen
1318      Gtk::TreeModel::Row rowInstr = *iterInstr;      Gtk::TreeModel::Row rowInstr = *iterInstr;
1319      rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();      rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1320      rowInstr[m_Columns.m_col_instr] = instrument;      rowInstr[m_Columns.m_col_instr] = instrument;
1321        file_changed();
1322  }  }
1323    
1324  void MainWindow::on_action_remove_instrument() {  void MainWindow::on_action_remove_instrument() {
1325      if (!file) return;      if (!file) return;
1326        if (file_is_shared) {
1327            Gtk::MessageDialog msg(
1328                *this,
1329                 _("You cannot delete an instrument from this file, since it's "
1330                   "currently used by the sampler."),
1331                 false, Gtk::MESSAGE_INFO
1332            );
1333            msg.run();
1334            return;
1335        }
1336    
1337      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
1338      Gtk::TreeModel::iterator it = sel->get_selected();      Gtk::TreeModel::iterator it = sel->get_selected();
1339      if (it) {      if (it) {
# Line 872  void MainWindow::on_action_remove_instru Line 1344  void MainWindow::on_action_remove_instru
1344              if (instr) file->DeleteInstrument(instr);              if (instr) file->DeleteInstrument(instr);
1345              // remove respective row from instruments tree view              // remove respective row from instruments tree view
1346              m_refTreeModel->erase(it);              m_refTreeModel->erase(it);
1347                file_changed();
1348          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1349              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1350              msg.run();              msg.run();
# Line 900  void MainWindow::on_action_add_group() { Line 1373  void MainWindow::on_action_add_group() {
1373      rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();      rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1374      rowGroup[m_SamplesModel.m_col_sample] = NULL;      rowGroup[m_SamplesModel.m_col_sample] = NULL;
1375      rowGroup[m_SamplesModel.m_col_group] = group;      rowGroup[m_SamplesModel.m_col_group] = group;
1376        file_changed();
1377  }  }
1378    
1379  void MainWindow::on_action_add_sample() {  void MainWindow::on_action_add_sample() {
# Line 925  void MainWindow::on_action_add_sample() Line 1399  void MainWindow::on_action_add_sample()
1399      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1400      dialog.set_select_multiple(true);      dialog.set_select_multiple(true);
1401      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1402      const char* supportedFileTypes[] = {      const char* const supportedFileTypes[] = {
1403          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1404          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1405          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
# Line 955  void MainWindow::on_action_add_sample() Line 1429  void MainWindow::on_action_add_sample()
1429                  int bitdepth;                  int bitdepth;
1430                  switch (info.format & 0xff) {                  switch (info.format & 0xff) {
1431                      case SF_FORMAT_PCM_S8:                      case SF_FORMAT_PCM_S8:
                         bitdepth = 16; // we simply convert to 16 bit for now  
                         break;  
1432                      case SF_FORMAT_PCM_16:                      case SF_FORMAT_PCM_16:
1433                        case SF_FORMAT_PCM_U8:
1434                          bitdepth = 16;                          bitdepth = 16;
1435                          break;                          break;
1436                      case SF_FORMAT_PCM_24:                      case SF_FORMAT_PCM_24:
                         bitdepth = 32; // we simply convert to 32 bit for now  
                         break;  
1437                      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;  
1438                      case SF_FORMAT_FLOAT:                      case SF_FORMAT_FLOAT:
                         bitdepth = 32;  
                         break;  
1439                      case SF_FORMAT_DOUBLE:                      case SF_FORMAT_DOUBLE:
1440                          bitdepth = 32; // I guess we will always truncate this to 32 bit                          bitdepth = 24;
1441                          break;                          break;
1442                      default:                      default:
1443                          sf_close(hFile); // close sound file                          sf_close(hFile); // close sound file
# Line 982  void MainWindow::on_action_add_sample() Line 1446  void MainWindow::on_action_add_sample()
1446                  // add a new sample to the .gig file                  // add a new sample to the .gig file
1447                  gig::Sample* sample = file->AddSample();                  gig::Sample* sample = file->AddSample();
1448                  // file name without path                  // file name without path
1449                  sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw();                  Glib::ustring filename = Glib::filename_display_basename(*iter);
1450                    // remove file extension if there is one
1451                    for (int i = 0; supportedFileTypes[i]; i++) {
1452                        if (Glib::str_has_suffix(filename, supportedFileTypes[i] + 1)) {
1453                            filename.erase(filename.length() - strlen(supportedFileTypes[i] + 1));
1454                            break;
1455                        }
1456                    }
1457                    sample->pInfo->Name = filename;
1458                  sample->Channels = info.channels;                  sample->Channels = info.channels;
1459                  sample->BitDepth = bitdepth;                  sample->BitDepth = bitdepth;
1460                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1461                  sample->SamplesPerSecond = info.samplerate;                  sample->SamplesPerSecond = info.samplerate;
1462                    sample->AverageBytesPerSecond = sample->FrameSize * sample->SamplesPerSecond;
1463                    sample->BlockAlign = sample->FrameSize;
1464                    sample->SamplesTotal = info.frames;
1465    
1466                    SF_INSTRUMENT instrument;
1467                    if (sf_command(hFile, SFC_GET_INSTRUMENT,
1468                                   &instrument, sizeof(instrument)) != SF_FALSE)
1469                    {
1470                        sample->MIDIUnityNote = instrument.basenote;
1471    
1472    #if HAVE_SF_INSTRUMENT_LOOPS
1473                        if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
1474                            sample->Loops = 1;
1475    
1476                            switch (instrument.loops[0].mode) {
1477                            case SF_LOOP_FORWARD:
1478                                sample->LoopType = gig::loop_type_normal;
1479                                break;
1480                            case SF_LOOP_BACKWARD:
1481                                sample->LoopType = gig::loop_type_backward;
1482                                break;
1483                            case SF_LOOP_ALTERNATING:
1484                                sample->LoopType = gig::loop_type_bidirectional;
1485                                break;
1486                            }
1487                            sample->LoopStart = instrument.loops[0].start;
1488                            sample->LoopEnd = instrument.loops[0].end;
1489                            sample->LoopPlayCount = instrument.loops[0].count;
1490                            sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
1491                        }
1492    #endif
1493                    }
1494    
1495                  // schedule resizing the sample (which will be done                  // schedule resizing the sample (which will be done
1496                  // physically when File::Save() is called)                  // physically when File::Save() is called)
1497                  sample->Resize(info.frames);                  sample->Resize(info.frames);
# Line 1002  void MainWindow::on_action_add_sample() Line 1507  void MainWindow::on_action_add_sample()
1507                  Gtk::TreeModel::iterator iterSample =                  Gtk::TreeModel::iterator iterSample =
1508                      m_refSamplesTreeModel->append(row.children());                      m_refSamplesTreeModel->append(row.children());
1509                  Gtk::TreeModel::Row rowSample = *iterSample;                  Gtk::TreeModel::Row rowSample = *iterSample;
1510                  rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();                  rowSample[m_SamplesModel.m_col_name]   = filename;
1511                  rowSample[m_SamplesModel.m_col_sample] = sample;                  rowSample[m_SamplesModel.m_col_sample] = sample;
1512                  rowSample[m_SamplesModel.m_col_group]  = NULL;                  rowSample[m_SamplesModel.m_col_group]  = NULL;
1513                  // close sound file                  // close sound file
1514                  sf_close(hFile);                  sf_close(hFile);
1515                    file_changed();
1516              } 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)
1517                  if (error_files.size()) error_files += "\n";                  if (error_files.size()) error_files += "\n";
1518                  error_files += *iter += " (" + what + ")";                  error_files += *iter += " (" + what + ")";
# Line 1014  void MainWindow::on_action_add_sample() Line 1520  void MainWindow::on_action_add_sample()
1520          }          }
1521          // 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
1522          if (error_files.size()) {          if (error_files.size()) {
1523              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;
1524                Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1525                msg.run();
1526            }
1527        }
1528    }
1529    
1530    void MainWindow::on_action_replace_all_samples_in_all_groups()
1531    {
1532        if (!file) return;
1533        Gtk::FileChooserDialog dialog(*this, _("Select Folder"),
1534                                      Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
1535        Gtk::Label description(
1536            _("This is a very specific function. It tries to replace all samples "
1537              "in the current gig file by samples located in the directory chosen "
1538              "by you above.\n\n"
1539              "It works like this: For each sample in the gig file it tries to "
1540              "find a sample file in the selected directory with the same name as "
1541              "the sample in the gig file. Optionally you can add a filename "
1542              "postfix below, which will be added to the filename expected to be "
1543              "found. That is, assume you have a gig file with a sample called "
1544              "'Snare', if you enter '.wav' below (like it's done by default), it "
1545              "assumes to find a sample file called 'Snare.wav' and will replace "
1546              "the sample in the gig file accordingly. If you don't need such a "
1547              "postfix, blank the field below. Any gig sample where no "
1548              "appropriate sample file could be found, will be reported and left "
1549              "untouched.\n\n")
1550        );
1551        description.set_line_wrap(true);
1552        Gtk::HBox entryArea;
1553        Gtk::Label entryLabel( _("Add Filename Extension: "), Gtk::ALIGN_RIGHT);
1554        Gtk::Entry postfixEntryBox;
1555        postfixEntryBox.set_text(".wav");
1556        entryArea.pack_start(entryLabel);
1557        entryArea.pack_start(postfixEntryBox);
1558        dialog.get_vbox()->pack_start(description, Gtk::PACK_SHRINK);
1559        dialog.get_vbox()->pack_start(entryArea, Gtk::PACK_SHRINK);
1560        description.show();
1561        entryLabel.show();
1562        postfixEntryBox.show();
1563        entryArea.show();
1564        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1565        dialog.add_button(_("Select"), Gtk::RESPONSE_OK);
1566        dialog.set_select_multiple(false);
1567        // fix label width (because Gtk by design doesn't
1568        // know anything about the parent's size)
1569    #if 0 //FIXME: doesn't work
1570        int dialogW, dialogH, labelW, labelH;
1571        dialog.get_size_request(dialogW, dialogH);
1572        description.get_size_request(labelW, labelH);
1573        std::cout << "dialog(" << dialogW << "," << dialogH << ")\nlabel(" << labelW << "," << labelH << ")\n" << std::flush;
1574        description.set_size_request(dialogW, labelH);
1575    #endif
1576        if (dialog.run() == Gtk::RESPONSE_OK)
1577        {
1578            Glib::ustring error_files;
1579            Glib::ustring folder = dialog.get_filename();
1580            for (gig::Sample* sample = file->GetFirstSample();
1581                 sample; sample = file->GetNextSample())
1582            {
1583                std::string filename =
1584                    folder + G_DIR_SEPARATOR_S + sample->pInfo->Name +
1585                    postfixEntryBox.get_text().raw();
1586                SF_INFO info;
1587                info.format = 0;
1588                SNDFILE* hFile = sf_open(filename.c_str(), SFM_READ, &info);
1589                try
1590                {
1591                    if (!hFile) throw std::string("could not open file");
1592                    int bitdepth;
1593                    switch (info.format & 0xff) {
1594                        case SF_FORMAT_PCM_S8:
1595                        case SF_FORMAT_PCM_16:
1596                        case SF_FORMAT_PCM_U8:
1597                            bitdepth = 16;
1598                            break;
1599                        case SF_FORMAT_PCM_24:
1600                        case SF_FORMAT_PCM_32:
1601                        case SF_FORMAT_FLOAT:
1602                        case SF_FORMAT_DOUBLE:
1603                            bitdepth = 24;
1604                            break;
1605                        default:
1606                            sf_close(hFile);
1607                            throw std::string("format not supported");
1608                    }
1609                    SampleImportItem sched_item;
1610                    sched_item.gig_sample  = sample;
1611                    sched_item.sample_path = filename;
1612                    m_SampleImportQueue.push_back(sched_item);
1613                    sf_close(hFile);
1614                    file_changed();
1615                }
1616                catch (std::string what)
1617                {
1618                    if (error_files.size()) error_files += "\n";
1619                        error_files += filename += " (" + what + ")";
1620                }
1621            }
1622            // show error message box when some file(s) could not be opened / added
1623            if (error_files.size()) {
1624                Glib::ustring txt =
1625                    _("Could not replace the following sample(s):\n") + error_files;
1626              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1627              msg.run();              msg.run();
1628          }          }
# Line 1040  void MainWindow::on_action_remove_sample Line 1648  void MainWindow::on_action_remove_sample
1648                       pSample; pSample = group->GetNextSample()) {                       pSample; pSample = group->GetNextSample()) {
1649                      members.push_back(pSample);                      members.push_back(pSample);
1650                  }                  }
1651                    // notify everybody that we're going to remove these samples
1652                    samples_to_be_removed_signal.emit(members);
1653                  // delete the group in the .gig file including the                  // delete the group in the .gig file including the
1654                  // samples that belong to the group                  // samples that belong to the group
1655                  file->DeleteGroup(group);                  file->DeleteGroup(group);
1656                    // notify that we're done with removal
1657                    samples_removed_signal.emit();
1658                  // if sample(s) were just previously added, remove                  // if sample(s) were just previously added, remove
1659                  // them from the import queue                  // them from the import queue
1660                  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 1669  void MainWindow::on_action_remove_sample
1669                          }                          }
1670                      }                      }
1671                  }                  }
1672                    file_changed();
1673              } else if (sample) {              } else if (sample) {
1674                    // notify everybody that we're going to remove this sample
1675                    std::list<gig::Sample*> lsamples;
1676                    lsamples.push_back(sample);
1677                    samples_to_be_removed_signal.emit(lsamples);
1678                  // remove sample from the .gig file                  // remove sample from the .gig file
1679                  file->DeleteSample(sample);                  file->DeleteSample(sample);
1680                    // notify that we're done with removal
1681                    samples_removed_signal.emit();
1682                  // if sample was just previously added, remove it from                  // if sample was just previously added, remove it from
1683                  // the import queue                  // the import queue
1684                  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 1690  void MainWindow::on_action_remove_sample
1690                          break;                          break;
1691                      }                      }
1692                  }                  }
1693                    dimreg_changed();
1694                    file_changed();
1695              }              }
1696              // remove respective row(s) from samples tree view              // remove respective row(s) from samples tree view
1697              m_refSamplesTreeModel->erase(it);              m_refSamplesTreeModel->erase(it);
1698          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1699                // pretend we're done with removal (i.e. to avoid dead locks)
1700                samples_removed_signal.emit();
1701                // show error message
1702              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1703              msg.run();              msg.run();
1704          }          }
1705      }      }
1706  }  }
1707    
1708    // For some reason drag_data_get gets called two times for each
1709    // drag'n'drop (at least when target is an Entry). This work-around
1710    // makes sure the code in drag_data_get and drop_drag_data_received is
1711    // only executed once, as drag_begin only gets called once.
1712    void MainWindow::on_sample_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
1713    {
1714        first_call_to_drag_data_get = true;
1715    }
1716    
1717  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>&,
1718                                                    Gtk::SelectionData& selection_data, guint, guint)                                                    Gtk::SelectionData& selection_data, guint, guint)
1719  {  {
1720        if (!first_call_to_drag_data_get) return;
1721        first_call_to_drag_data_get = false;
1722    
1723      // get selected sample      // get selected sample
1724      gig::Sample* sample = NULL;      gig::Sample* sample = NULL;
1725      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 1737  void MainWindow::on_sample_label_drop_dr
1737      const Glib::RefPtr<Gdk::DragContext>& context, int, int,      const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1738      const Gtk::SelectionData& selection_data, guint, guint time)      const Gtk::SelectionData& selection_data, guint, guint time)
1739  {  {
     gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();  
1740      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1741    
1742      if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {      if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
1743          if (sample != dimregion->pSample) {          std::cout << "Drop received sample \"" <<
1744              dimregion->pSample = sample;              sample->pInfo->Name << "\"" << std::endl;
1745              dimreg_edit.wSample->set_text(dimregion->pSample->pInfo->Name.c_str());          // drop success
1746              std::cout << "Drop received sample \"" <<          context->drop_reply(true, time);
1747                  dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;  
1748              // drop success          //TODO: we should better move most of the following code to DimRegionEdit::set_sample()
1749              context->drop_reply(true, time);  
1750              return;          // notify everybody that we're going to alter the region
1751            gig::Region* region = m_RegionChooser.get_region();
1752            region_to_be_changed_signal.emit(region);
1753    
1754            // find the samplechannel dimension
1755            gig::dimension_def_t* stereo_dimension = 0;
1756            for (int i = 0 ; i < region->Dimensions ; i++) {
1757                if (region->pDimensionDefinitions[i].dimension ==
1758                    gig::dimension_samplechannel) {
1759                    stereo_dimension = &region->pDimensionDefinitions[i];
1760                    break;
1761                }
1762            }
1763            bool channels_changed = false;
1764            if (sample->Channels == 1 && stereo_dimension) {
1765                // remove the samplechannel dimension
1766                region->DeleteDimension(stereo_dimension);
1767                channels_changed = true;
1768                region_changed();
1769          }          }
1770            dimreg_edit.set_sample(sample);
1771    
1772            if (sample->Channels == 2 && !stereo_dimension) {
1773                // add samplechannel dimension
1774                gig::dimension_def_t dim;
1775                dim.dimension = gig::dimension_samplechannel;
1776                dim.bits = 1;
1777                dim.zones = 2;
1778                region->AddDimension(&dim);
1779                channels_changed = true;
1780                region_changed();
1781            }
1782            if (channels_changed) {
1783                // unmap all samples with wrong number of channels
1784                // TODO: maybe there should be a warning dialog for this
1785                for (int i = 0 ; i < region->DimensionRegions ; i++) {
1786                    gig::DimensionRegion* d = region->pDimensionRegions[i];
1787                    if (d->pSample && d->pSample->Channels != sample->Channels) {
1788                        gig::Sample* oldref = d->pSample;
1789                        d->pSample = NULL;
1790                        sample_ref_changed_signal.emit(oldref, NULL);
1791                    }
1792                }
1793            }
1794    
1795            // notify we're done with altering
1796            region_changed_signal.emit(region);
1797    
1798            file_changed();
1799    
1800            return;
1801      }      }
1802      // drop failed      // drop failed
1803      context->drop_reply(false, time);      context->drop_reply(false, time);
# Line 1127  void MainWindow::sample_name_changed(con Line 1811  void MainWindow::sample_name_changed(con
1811      gig::Group* group   = row[m_SamplesModel.m_col_group];      gig::Group* group   = row[m_SamplesModel.m_col_group];
1812      gig::Sample* sample = row[m_SamplesModel.m_col_sample];      gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1813      if (group) {      if (group) {
1814          group->Name = name;          if (group->Name != name) {
1815                group->Name = name;
1816                printf("group name changed\n");
1817                file_changed();
1818            }
1819      } else if (sample) {      } else if (sample) {
1820          sample->pInfo->Name = name.raw();          if (sample->pInfo->Name != name.raw()) {
1821                sample->pInfo->Name = name.raw();
1822                printf("sample name changed\n");
1823                file_changed();
1824            }
1825      }      }
1826  }  }
1827    
# Line 1139  void MainWindow::instrument_name_changed Line 1831  void MainWindow::instrument_name_changed
1831      Gtk::TreeModel::Row row = *iter;      Gtk::TreeModel::Row row = *iter;
1832      Glib::ustring name = row[m_Columns.m_col_name];      Glib::ustring name = row[m_Columns.m_col_name];
1833      gig::Instrument* instrument = row[m_Columns.m_col_instr];      gig::Instrument* instrument = row[m_Columns.m_col_instr];
1834      if (instrument) instrument->pInfo->Name = name.raw();      if (instrument && instrument->pInfo->Name != name.raw()) {
1835            instrument->pInfo->Name = name.raw();
1836            file_changed();
1837        }
1838    }
1839    
1840    void MainWindow::set_file_is_shared(bool b) {
1841        this->file_is_shared = b;
1842    
1843        if (file_is_shared) {
1844            m_AttachedStateLabel.set_label(_("live-mode"));
1845            m_AttachedStateImage.set(
1846                Gdk::Pixbuf::create_from_xpm_data(status_attached_xpm)
1847            );
1848        } else {
1849            m_AttachedStateLabel.set_label(_("stand-alone"));
1850            m_AttachedStateImage.set(
1851                Gdk::Pixbuf::create_from_xpm_data(status_detached_xpm)
1852            );
1853        }
1854    }
1855    
1856    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {
1857        return file_structure_to_be_changed_signal;
1858    }
1859    
1860    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_changed() {
1861        return file_structure_changed_signal;
1862    }
1863    
1864    sigc::signal<void, std::list<gig::Sample*> >& MainWindow::signal_samples_to_be_removed() {
1865        return samples_to_be_removed_signal;
1866    }
1867    
1868    sigc::signal<void>& MainWindow::signal_samples_removed() {
1869        return samples_removed_signal;
1870    }
1871    
1872    sigc::signal<void, gig::Region*>& MainWindow::signal_region_to_be_changed() {
1873        return region_to_be_changed_signal;
1874    }
1875    
1876    sigc::signal<void, gig::Region*>& MainWindow::signal_region_changed() {
1877        return region_changed_signal;
1878    }
1879    
1880    sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& MainWindow::signal_sample_ref_changed() {
1881        return sample_ref_changed_signal;
1882    }
1883    
1884    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_to_be_changed() {
1885        return dimreg_to_be_changed_signal;
1886    }
1887    
1888    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_changed() {
1889        return dimreg_changed_signal;
1890    }
1891    
1892    sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_note_on() {
1893        return note_on_signal;
1894    }
1895    
1896    sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_note_off() {
1897        return note_off_signal;
1898    }
1899    
1900    sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_keyboard_key_hit() {
1901        return m_RegionChooser.signal_keyboard_key_hit();
1902    }
1903    
1904    sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_keyboard_key_released() {
1905        return m_RegionChooser.signal_keyboard_key_released();
1906  }  }

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

  ViewVC Help
Powered by ViewVC