/[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 2151 by persson, Sun Nov 21 12:38:41 2010 UTC revision 3225 by schoenebeck, Fri May 26 22:10:16 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2010 Andreas Persson   * Copyright (C) 2006-2017 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 20  Line 20 
20  #include <iostream>  #include <iostream>
21  #include <cstring>  #include <cstring>
22    
23    #include <glibmmconfig.h>
24    // threads.h must be included first to be able to build with
25    // G_DISABLE_DEPRECATED
26    #if (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION == 31 && GLIBMM_MICRO_VERSION >= 2) || \
27        (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION > 31) || GLIBMM_MAJOR_VERSION > 2
28    #include <glibmm/threads.h>
29    #endif
30    
31    #include <glibmm/convert.h>
32    #include <glibmm/dispatcher.h>
33    #include <glibmm/miscutils.h>
34    #include <glibmm/stringutils.h>
35  #include <gtkmm/aboutdialog.h>  #include <gtkmm/aboutdialog.h>
36  #include <gtkmm/filechooserdialog.h>  #include <gtkmm/filechooserdialog.h>
37  #include <gtkmm/messagedialog.h>  #include <gtkmm/messagedialog.h>
# Line 27  Line 39 
39  #include <gtkmm/targetentry.h>  #include <gtkmm/targetentry.h>
40  #include <gtkmm/main.h>  #include <gtkmm/main.h>
41  #include <gtkmm/toggleaction.h>  #include <gtkmm/toggleaction.h>
42    #include <gtkmm/accelmap.h>
43    #if GTKMM_MAJOR_VERSION < 3
44  #include "wrapLabel.hh"  #include "wrapLabel.hh"
45    #endif
46    
47  #include "global.h"  #include "global.h"
48    #include "compat.h"
 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 18) || GTKMM_MAJOR_VERSION < 2  
 #define set_can_default() set_flags(Gtk::CAN_DEFAULT)  
 #endif  
49    
50  #include <stdio.h>  #include <stdio.h>
51  #include <sndfile.h>  #include <sndfile.h>
52    #include <assert.h>
53    
54  #include "mainwindow.h"  #include "mainwindow.h"
55    #include "Settings.h"
56    #include "CombineInstrumentsDialog.h"
57    #include "scripteditor.h"
58    #include "scriptslots.h"
59    #include "ReferencesView.h"
60  #include "../../gfx/status_attached.xpm"  #include "../../gfx/status_attached.xpm"
61  #include "../../gfx/status_detached.xpm"  #include "../../gfx/status_detached.xpm"
62    #include "gfx/builtinpix.h"
63  template<class T> inline std::string ToString(T o) {  #include "MacroEditor.h"
64      std::stringstream ss;  #include "MacrosSetup.h"
     ss << o;  
     return ss.str();  
 }  
   
 Table::Table(int x, int y) : Gtk::Table(x, y), rowno(0) {  }  
   
 void Table::add(BoolEntry& boolentry)  
 {  
     attach(boolentry.widget, 0, 2, rowno, rowno + 1,  
            Gtk::FILL, Gtk::SHRINK);  
     rowno++;  
 }  
   
 void Table::add(BoolEntryPlus6& boolentry)  
 {  
     attach(boolentry.widget, 0, 2, rowno, rowno + 1,  
            Gtk::FILL, Gtk::SHRINK);  
     rowno++;  
 }  
   
 void Table::add(LabelWidget& prop)  
 {  
     attach(prop.label, 1, 2, rowno, rowno + 1,  
            Gtk::FILL, Gtk::SHRINK);  
     attach(prop.widget, 2, 3, rowno, rowno + 1,  
            Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK);  
     rowno++;  
 }  
65    
66  MainWindow::MainWindow() :  MainWindow::MainWindow() :
67        m_DimRegionChooser(*this),
68      dimreg_label(_("Changes apply to:")),      dimreg_label(_("Changes apply to:")),
69      dimreg_all_regions(_("all regions")),      dimreg_all_regions(_("all regions")),
70      dimreg_all_dimregs(_("all dimension splits")),      dimreg_all_dimregs(_("all dimension splits")),
71      dimreg_stereo(_("both channels"))      dimreg_stereo(_("both channels")),
72        labelLegend(_("Legend:")),
73        labelNoSample(_(" No Sample")),
74        labelMissingSample(_(" Missing some Sample(s)")),
75        labelLooped(_(" Looped")),
76        labelSomeLoops(_(" Some Loop(s)"))
77  {  {
78        loadBuiltInPix();
79    
80  //    set_border_width(5);  //    set_border_width(5);
 //    set_default_size(400, 200);  
81    
82        if (!Settings::singleton()->autoRestoreWindowDimension) {
83            set_default_size(800, 600);
84            set_position(Gtk::WIN_POS_CENTER);
85        }
86    
87      add(m_VBox);      add(m_VBox);
88    
89      // Handle selection      // Handle selection
90      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      m_TreeView.get_selection()->signal_changed().connect(
     tree_sel_ref->signal_changed().connect(  
91          sigc::mem_fun(*this, &MainWindow::on_sel_change));          sigc::mem_fun(*this, &MainWindow::on_sel_change));
92    
93      // m_TreeView.set_reorderable();      // m_TreeView.set_reorderable();
# Line 104  MainWindow::MainWindow() : Line 103  MainWindow::MainWindow() :
103      m_ScrolledWindowSamples.add(m_TreeViewSamples);      m_ScrolledWindowSamples.add(m_TreeViewSamples);
104      m_ScrolledWindowSamples.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);      m_ScrolledWindowSamples.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
105    
106        m_ScrolledWindowScripts.add(m_TreeViewScripts);
107        m_ScrolledWindowScripts.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
108    
109    
110      m_TreeViewNotebook.set_size_request(300);      m_TreeViewNotebook.set_size_request(300);
111    
# Line 115  MainWindow::MainWindow() : Line 117  MainWindow::MainWindow() :
117      dimreg_hbox.add(dimreg_stereo);      dimreg_hbox.add(dimreg_stereo);
118      dimreg_vbox.add(dimreg_edit);      dimreg_vbox.add(dimreg_edit);
119      dimreg_vbox.pack_start(dimreg_hbox, Gtk::PACK_SHRINK);      dimreg_vbox.pack_start(dimreg_hbox, Gtk::PACK_SHRINK);
120        {
121            legend_hbox.add(labelLegend);
122    
123            imageNoSample.set(redDot);
124            imageNoSample.set_alignment(Gtk::ALIGN_END);
125            labelNoSample.set_alignment(Gtk::ALIGN_START);
126            legend_hbox.add(imageNoSample);
127            legend_hbox.add(labelNoSample);
128    
129            imageMissingSample.set(yellowDot);
130            imageMissingSample.set_alignment(Gtk::ALIGN_END);
131            labelMissingSample.set_alignment(Gtk::ALIGN_START);
132            legend_hbox.add(imageMissingSample);
133            legend_hbox.add(labelMissingSample);
134    
135            imageLooped.set(blackLoop);
136            imageLooped.set_alignment(Gtk::ALIGN_END);
137            labelLooped.set_alignment(Gtk::ALIGN_START);
138            legend_hbox.add(imageLooped);
139            legend_hbox.add(labelLooped);
140    
141            imageSomeLoops.set(grayLoop);
142            imageSomeLoops.set_alignment(Gtk::ALIGN_END);
143            labelSomeLoops.set_alignment(Gtk::ALIGN_START);
144            legend_hbox.add(imageSomeLoops);
145            legend_hbox.add(labelSomeLoops);
146    
147            legend_hbox.show_all_children();
148        }
149        dimreg_vbox.pack_start(legend_hbox, Gtk::PACK_SHRINK);
150      m_HPaned.add2(dimreg_vbox);      m_HPaned.add2(dimreg_vbox);
151    
152        dimreg_label.set_tooltip_text(_("To automatically apply your changes above globally to the entire instrument, check all 3 check boxes on the right."));
153        dimreg_all_regions.set_tooltip_text(_("If checked: all changes you perform above will automatically be applied to all regions of this instrument as well."));
154        dimreg_all_dimregs.set_tooltip_text(_("If checked: all changes you perform above will automatically be applied as well to all dimension splits of the region selected below."));
155        dimreg_stereo.set_tooltip_text(_("If checked: all changes you perform above will automatically be applied to both audio channel splits (only if a \"stereo\" dimension is defined below)."));
156    
157      m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, _("Samples"));      m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, _("Samples"));
158      m_TreeViewNotebook.append_page(m_ScrolledWindow, _("Instruments"));      m_TreeViewNotebook.append_page(m_ScrolledWindow, _("Instruments"));
159        m_TreeViewNotebook.append_page(m_ScrolledWindowScripts, _("Scripts"));
160    
161      actionGroup = Gtk::ActionGroup::create();      actionGroup = Gtk::ActionGroup::create();
162    
# Line 151  MainWindow::MainWindow() : Line 187  MainWindow::MainWindow() :
187                                           Gtk::Stock::PROPERTIES),                                           Gtk::Stock::PROPERTIES),
188                       sigc::mem_fun(                       sigc::mem_fun(
189                           *this, &MainWindow::show_instr_props));                           *this, &MainWindow::show_instr_props));
190        actionGroup->add(Gtk::Action::create("MidiRules",
191                                             _("_Midi Rules...")),
192                         sigc::mem_fun(
193                             *this, &MainWindow::show_midi_rules));
194        actionGroup->add(Gtk::Action::create("ScriptSlots",
195                                             _("_Script Slots...")),
196                         sigc::mem_fun(
197                             *this, &MainWindow::show_script_slots));
198      actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),      actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),
199                       sigc::mem_fun(                       sigc::mem_fun(
200                           *this, &MainWindow::on_action_quit));                           *this, &MainWindow::on_action_quit));
201      actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));      actionGroup->add(
202            Gtk::Action::create("MenuSample", _("_Sample")),
203            sigc::mem_fun(*this, &MainWindow::show_samples_tab)
204        );
205        actionGroup->add(
206            Gtk::Action::create("MenuInstrument", _("_Instrument")),
207            sigc::mem_fun(*this, &MainWindow::show_intruments_tab)
208        );
209        actionGroup->add(
210            Gtk::Action::create("MenuScript", _("Scr_ipt")),
211            sigc::mem_fun(*this, &MainWindow::show_scripts_tab)
212        );
213        actionGroup->add(Gtk::Action::create("AllInstruments", _("_Select")));
214    
215        actionGroup->add(Gtk::Action::create("MenuEdit", _("_Edit")));
216    
217        const Gdk::ModifierType primaryModifierKey =
218    #if defined(__APPLE__)
219        Gdk::META_MASK; // Cmd key on Mac
220    #else
221        Gdk::CONTROL_MASK; // Ctrl key on all other OSs
222    #endif
223    
224        actionGroup->add(Gtk::Action::create("CopyDimRgn",
225                                             _("Copy selected dimension region")),
226                         Gtk::AccelKey(GDK_KEY_c, Gdk::MOD1_MASK),
227                         sigc::mem_fun(*this, &MainWindow::copy_selected_dimrgn));
228    
229        actionGroup->add(Gtk::Action::create("PasteDimRgn",
230                                             _("Paste dimension region")),
231                         Gtk::AccelKey(GDK_KEY_v, Gdk::MOD1_MASK),
232                         sigc::mem_fun(*this, &MainWindow::paste_copied_dimrgn));
233    
234        actionGroup->add(Gtk::Action::create("AdjustClipboard",
235                                             _("Adjust Clipboard Content")),
236                         Gtk::AccelKey(GDK_KEY_x, Gdk::MOD1_MASK),
237                         sigc::mem_fun(*this, &MainWindow::adjust_clipboard_content));
238    
239        actionGroup->add(Gtk::Action::create("SelectPrevRegion",
240                                             _("Select Previous Region")),
241                         Gtk::AccelKey(GDK_KEY_Left, primaryModifierKey),
242                         sigc::mem_fun(*this, &MainWindow::select_prev_region));
243    
244        actionGroup->add(Gtk::Action::create("SelectNextRegion",
245                                             _("Select Next Region")),
246                         Gtk::AccelKey(GDK_KEY_Right, primaryModifierKey),
247                         sigc::mem_fun(*this, &MainWindow::select_next_region));
248    
249        actionGroup->add(Gtk::Action::create("SelectPrevDimRgnZone",
250                                             _("Select Previous Dimension Region Zone")),
251                         Gtk::AccelKey(GDK_KEY_Left, Gdk::MOD1_MASK),
252                         sigc::mem_fun(*this, &MainWindow::select_prev_dim_rgn_zone));
253    
254        actionGroup->add(Gtk::Action::create("SelectNextDimRgnZone",
255                                             _("Select Next Dimension Region Zone")),
256                         Gtk::AccelKey(GDK_KEY_Right, Gdk::MOD1_MASK),
257                         sigc::mem_fun(*this, &MainWindow::select_next_dim_rgn_zone));
258    
259        actionGroup->add(Gtk::Action::create("SelectPrevDimension",
260                                             _("Select Previous Dimension")),
261                         Gtk::AccelKey(GDK_KEY_Up, Gdk::MOD1_MASK),
262                         sigc::mem_fun(*this, &MainWindow::select_prev_dimension));
263    
264        actionGroup->add(Gtk::Action::create("SelectNextDimension",
265                                             _("Select Next Dimension")),
266                         Gtk::AccelKey(GDK_KEY_Down, Gdk::MOD1_MASK),
267                         sigc::mem_fun(*this, &MainWindow::select_next_dimension));
268    
269        actionGroup->add(Gtk::Action::create("SelectAddPrevDimRgnZone",
270                                             _("Add Previous Dimension Region Zone to Selection")),
271                         Gtk::AccelKey(GDK_KEY_Left, Gdk::MOD1_MASK | Gdk::SHIFT_MASK),
272                         sigc::mem_fun(*this, &MainWindow::select_add_prev_dim_rgn_zone));
273    
274        actionGroup->add(Gtk::Action::create("SelectAddNextDimRgnZone",
275                                             _("Add Next Dimension Region Zone to Selection")),
276                         Gtk::AccelKey(GDK_KEY_Right, Gdk::MOD1_MASK | Gdk::SHIFT_MASK),
277                         sigc::mem_fun(*this, &MainWindow::select_add_next_dim_rgn_zone));
278    
     actionGroup->add(Gtk::Action::create("MenuView", _("_View")));  
279      Glib::RefPtr<Gtk::ToggleAction> toggle_action =      Glib::RefPtr<Gtk::ToggleAction> toggle_action =
280            Gtk::ToggleAction::create("CopySampleUnity", _("Copy Sample's _Unity Note"));
281        toggle_action->set_active(true);
282        actionGroup->add(toggle_action);
283    
284        toggle_action =
285            Gtk::ToggleAction::create("CopySampleTune", _("Copy Sample's _Fine Tune"));
286        toggle_action->set_active(true);
287        actionGroup->add(toggle_action);
288    
289        toggle_action =
290            Gtk::ToggleAction::create("CopySampleLoop", _("Copy Sample's _Loop Points"));
291        toggle_action->set_active(true);
292        actionGroup->add(toggle_action);
293    
294    
295        actionGroup->add(Gtk::Action::create("MenuMacro", _("_Macro")));
296    
297    
298        actionGroup->add(Gtk::Action::create("MenuView", _("Vie_w")));
299        toggle_action =
300          Gtk::ToggleAction::create("Statusbar", _("_Statusbar"));          Gtk::ToggleAction::create("Statusbar", _("_Statusbar"));
301      toggle_action->set_active(true);      toggle_action->set_active(true);
302      actionGroup->add(toggle_action,      actionGroup->add(toggle_action,
303                       sigc::mem_fun(                       sigc::mem_fun(
304                           *this, &MainWindow::on_action_view_status_bar));                           *this, &MainWindow::on_action_view_status_bar));
305    
306        toggle_action =
307            Gtk::ToggleAction::create("AutoRestoreWinDim", _("_Auto Restore Window Dimension"));
308        toggle_action->set_active(Settings::singleton()->autoRestoreWindowDimension);
309        actionGroup->add(toggle_action,
310                         sigc::mem_fun(
311                             *this, &MainWindow::on_auto_restore_win_dim));
312    
313        toggle_action =
314            Gtk::ToggleAction::create("SaveWithTemporaryFile", _("Save with _temporary file"));
315        toggle_action->set_active(Settings::singleton()->saveWithTemporaryFile);
316        actionGroup->add(toggle_action,
317                         sigc::mem_fun(
318                             *this, &MainWindow::on_save_with_temporary_file));
319    
320        actionGroup->add(
321            Gtk::Action::create("RefreshAll", _("_Refresh All")),
322            sigc::mem_fun(*this, &MainWindow::on_action_refresh_all)
323        );                
324    
325      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);
326      actionGroup->add(Gtk::Action::create("MenuHelp",      actionGroup->add(Gtk::Action::create("MenuHelp",
327                                           action->property_label()));                                           action->property_label()));
# Line 175  MainWindow::MainWindow() : Line 333  MainWindow::MainWindow() :
333          sigc::mem_fun(*this, &MainWindow::on_action_add_instrument)          sigc::mem_fun(*this, &MainWindow::on_action_add_instrument)
334      );      );
335      actionGroup->add(      actionGroup->add(
336            Gtk::Action::create("DupInstrument", _("_Duplicate Instrument")),
337            sigc::mem_fun(*this, &MainWindow::on_action_duplicate_instrument)
338        );
339        actionGroup->add(
340          Gtk::Action::create("RemoveInstrument", Gtk::Stock::REMOVE),          Gtk::Action::create("RemoveInstrument", Gtk::Stock::REMOVE),
341          sigc::mem_fun(*this, &MainWindow::on_action_remove_instrument)          sigc::mem_fun(*this, &MainWindow::on_action_remove_instrument)
342      );      );
343    
344    
345        actionGroup->add(Gtk::Action::create("MenuSettings", _("_Settings")));
346        
347        toggle_action =
348            Gtk::ToggleAction::create("WarnUserOnExtensions", _("Show warning on format _extensions"));
349        toggle_action->set_active(Settings::singleton()->warnUserOnExtensions);
350        actionGroup->add(
351            toggle_action,
352            sigc::mem_fun(*this, &MainWindow::on_action_warn_user_on_extensions)
353        );
354    
355        toggle_action =
356            Gtk::ToggleAction::create("SyncSamplerInstrumentSelection", _("Synchronize sampler's instrument selection"));
357        toggle_action->set_active(Settings::singleton()->syncSamplerInstrumentSelection);
358        actionGroup->add(
359            toggle_action,
360            sigc::mem_fun(*this, &MainWindow::on_action_sync_sampler_instrument_selection)
361        );
362    
363        toggle_action =
364            Gtk::ToggleAction::create("MoveRootNoteWithRegionMoved", _("Move root note with region moved"));
365        toggle_action->set_active(Settings::singleton()->moveRootNoteWithRegionMoved);
366        actionGroup->add(
367            toggle_action,
368            sigc::mem_fun(*this, &MainWindow::on_action_move_root_note_with_region_moved)
369        );
370    
371    
372        actionGroup->add(Gtk::Action::create("MenuTools", _("_Tools")));
373    
374        actionGroup->add(
375            Gtk::Action::create("CombineInstruments", _("_Combine Instruments...")),
376            sigc::mem_fun(*this, &MainWindow::on_action_combine_instruments)
377        );
378    
379        actionGroup->add(
380            Gtk::Action::create("MergeFiles", _("_Merge Files...")),
381            sigc::mem_fun(*this, &MainWindow::on_action_merge_files)
382        );
383    
384    
385      // sample right-click popup actions      // sample right-click popup actions
386      actionGroup->add(      actionGroup->add(
387          Gtk::Action::create("SampleProperties", Gtk::Stock::PROPERTIES),          Gtk::Action::create("SampleProperties", Gtk::Stock::PROPERTIES),
# Line 197  MainWindow::MainWindow() : Line 400  MainWindow::MainWindow() :
400          sigc::mem_fun(*this, &MainWindow::on_action_remove_sample)          sigc::mem_fun(*this, &MainWindow::on_action_remove_sample)
401      );      );
402      actionGroup->add(      actionGroup->add(
403            Gtk::Action::create("RemoveUnusedSamples", _("Remove _Unused Samples")),
404            sigc::mem_fun(*this, &MainWindow::on_action_remove_unused_samples)
405        );
406        actionGroup->add(
407            Gtk::Action::create("ShowSampleRefs", _("Show References...")),
408            sigc::mem_fun(*this, &MainWindow::on_action_view_references)
409        );
410        actionGroup->add(
411            Gtk::Action::create("ReplaceSample",
412                                _("Replace Sample...")),
413            sigc::mem_fun(*this, &MainWindow::on_action_replace_sample)
414        );
415        actionGroup->add(
416          Gtk::Action::create("ReplaceAllSamplesInAllGroups",          Gtk::Action::create("ReplaceAllSamplesInAllGroups",
417                              _("Replace All Samples in All Groups...")),                              _("Replace All Samples in All Groups...")),
418          sigc::mem_fun(*this, &MainWindow::on_action_replace_all_samples_in_all_groups)          sigc::mem_fun(*this, &MainWindow::on_action_replace_all_samples_in_all_groups)
419      );      );
420        
421        // script right-click popup actions
422        actionGroup->add(
423            Gtk::Action::create("AddScriptGroup", _("Add _Group")),
424            sigc::mem_fun(*this, &MainWindow::on_action_add_script_group)
425        );
426        actionGroup->add(
427            Gtk::Action::create("AddScript", _("Add _Script")),
428            sigc::mem_fun(*this, &MainWindow::on_action_add_script)
429        );
430        actionGroup->add(
431            Gtk::Action::create("EditScript", _("_Edit Script...")),
432            sigc::mem_fun(*this, &MainWindow::on_action_edit_script)
433        );
434        actionGroup->add(
435            Gtk::Action::create("RemoveScript", Gtk::Stock::REMOVE),
436            sigc::mem_fun(*this, &MainWindow::on_action_remove_script)
437        );
438    
439      uiManager = Gtk::UIManager::create();      uiManager = Gtk::UIManager::create();
440      uiManager->insert_action_group(actionGroup);      uiManager->insert_action_group(actionGroup);
# Line 220  MainWindow::MainWindow() : Line 454  MainWindow::MainWindow() :
454          "      <separator/>"          "      <separator/>"
455          "      <menuitem action='Quit'/>"          "      <menuitem action='Quit'/>"
456          "    </menu>"          "    </menu>"
457            "    <menu action='MenuEdit'>"
458            "      <menuitem action='CopyDimRgn'/>"
459            "      <menuitem action='AdjustClipboard'/>"
460            "      <menuitem action='PasteDimRgn'/>"
461            "      <separator/>"
462            "      <menuitem action='SelectPrevRegion'/>"
463            "      <menuitem action='SelectNextRegion'/>"
464            "      <separator/>"
465            "      <menuitem action='SelectPrevDimension'/>"
466            "      <menuitem action='SelectNextDimension'/>"
467            "      <menuitem action='SelectPrevDimRgnZone'/>"
468            "      <menuitem action='SelectNextDimRgnZone'/>"
469            "      <menuitem action='SelectAddPrevDimRgnZone'/>"
470            "      <menuitem action='SelectAddNextDimRgnZone'/>"
471            "      <separator/>"
472            "      <menuitem action='CopySampleUnity'/>"
473            "      <menuitem action='CopySampleTune'/>"
474            "      <menuitem action='CopySampleLoop'/>"
475            "    </menu>"
476            "    <menu action='MenuMacro'>"
477            "    </menu>"
478            "    <menu action='MenuSample'>"
479            "      <menuitem action='SampleProperties'/>"
480            "      <menuitem action='AddGroup'/>"
481            "      <menuitem action='AddSample'/>"
482            "      <menuitem action='ShowSampleRefs'/>"
483            "      <menuitem action='ReplaceSample' />"
484            "      <menuitem action='ReplaceAllSamplesInAllGroups' />"
485            "      <separator/>"
486            "      <menuitem action='RemoveSample'/>"
487            "      <menuitem action='RemoveUnusedSamples'/>"
488            "    </menu>"
489          "    <menu action='MenuInstrument'>"          "    <menu action='MenuInstrument'>"
490            "      <menu action='AllInstruments'>"
491            "      </menu>"
492            "      <separator/>"
493            "      <menuitem action='InstrProperties'/>"
494            "      <menuitem action='MidiRules'/>"
495            "      <menuitem action='ScriptSlots'/>"
496            "      <menuitem action='AddInstrument'/>"
497            "      <menuitem action='DupInstrument'/>"
498            "      <separator/>"
499            "      <menuitem action='RemoveInstrument'/>"
500            "    </menu>"
501            "    <menu action='MenuScript'>"
502            "      <menuitem action='AddScriptGroup'/>"
503            "      <menuitem action='AddScript'/>"
504            "      <menuitem action='EditScript'/>"
505            "      <separator/>"
506            "      <menuitem action='RemoveScript'/>"
507          "    </menu>"          "    </menu>"
508          "    <menu action='MenuView'>"          "    <menu action='MenuView'>"
509          "      <menuitem action='Statusbar'/>"          "      <menuitem action='Statusbar'/>"
510            "      <menuitem action='AutoRestoreWinDim'/>"
511            "      <separator/>"
512            "      <menuitem action='RefreshAll'/>"
513            "    </menu>"
514            "    <menu action='MenuTools'>"
515            "      <menuitem action='CombineInstruments'/>"
516            "      <menuitem action='MergeFiles'/>"
517            "    </menu>"
518            "    <menu action='MenuSettings'>"
519            "      <menuitem action='WarnUserOnExtensions'/>"
520            "      <menuitem action='SyncSamplerInstrumentSelection'/>"
521            "      <menuitem action='MoveRootNoteWithRegionMoved'/>"
522            "      <menuitem action='SaveWithTemporaryFile'/>"
523          "    </menu>"          "    </menu>"
524          "    <menu action='MenuHelp'>"          "    <menu action='MenuHelp'>"
525          "      <menuitem action='About'/>"          "      <menuitem action='About'/>"
# Line 231  MainWindow::MainWindow() : Line 527  MainWindow::MainWindow() :
527          "  </menubar>"          "  </menubar>"
528          "  <popup name='PopupMenu'>"          "  <popup name='PopupMenu'>"
529          "    <menuitem action='InstrProperties'/>"          "    <menuitem action='InstrProperties'/>"
530            "    <menuitem action='MidiRules'/>"
531            "    <menuitem action='ScriptSlots'/>"
532          "    <menuitem action='AddInstrument'/>"          "    <menuitem action='AddInstrument'/>"
533            "    <menuitem action='DupInstrument'/>"
534          "    <separator/>"          "    <separator/>"
535          "    <menuitem action='RemoveInstrument'/>"          "    <menuitem action='RemoveInstrument'/>"
536          "  </popup>"          "  </popup>"
# Line 239  MainWindow::MainWindow() : Line 538  MainWindow::MainWindow() :
538          "    <menuitem action='SampleProperties'/>"          "    <menuitem action='SampleProperties'/>"
539          "    <menuitem action='AddGroup'/>"          "    <menuitem action='AddGroup'/>"
540          "    <menuitem action='AddSample'/>"          "    <menuitem action='AddSample'/>"
541          "    <menuitem action='ReplaceAllSamplesInAllGroups' />"          "    <menuitem action='ShowSampleRefs'/>"
542            "    <menuitem action='ReplaceSample' />"
543            "    <menuitem action='ReplaceAllSamplesInAllGroups' />"
544          "    <separator/>"          "    <separator/>"
545          "    <menuitem action='RemoveSample'/>"          "    <menuitem action='RemoveSample'/>"
546            "    <menuitem action='RemoveUnusedSamples'/>"
547            "  </popup>"
548            "  <popup name='ScriptPopupMenu'>"
549            "    <menuitem action='AddScriptGroup'/>"
550            "    <menuitem action='AddScript'/>"
551            "    <menuitem action='EditScript'/>"
552            "    <separator/>"
553            "    <menuitem action='RemoveScript'/>"
554          "  </popup>"          "  </popup>"
555          "</ui>";          "</ui>";
556      uiManager->add_ui_from_string(ui_info);      uiManager->add_ui_from_string(ui_info);
557    
558      popup_menu = dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/PopupMenu"));      popup_menu = dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/PopupMenu"));
559        
560        // Set tooltips for menu items (for some reason, setting a tooltip on the
561        // respective Gtk::Action objects above will simply be ignored, no matter
562        // if using Gtk::Action::set_tooltip() or passing the tooltip string on
563        // Gtk::Action::create()).
564        {
565            Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
566                uiManager->get_widget("/MenuBar/MenuEdit/CopySampleUnity"));
567            item->set_tooltip_text(_("Used when dragging a sample to a region's sample reference field. You may disable this for example if you want to replace an existing sample in a region with a new sample, but don't want that the region's current unity note setting will be altered by this action."));
568        }
569        {
570            Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
571                uiManager->get_widget("/MenuBar/MenuEdit/CopySampleTune"));
572            item->set_tooltip_text(_("Used when dragging a sample to a region's sample reference field. You may disable this for example if you want to replace an existing sample in a region with a new sample, but don't want that the region's current sample playback tuning will be altered by this action."));
573        }
574        {
575            Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
576                uiManager->get_widget("/MenuBar/MenuEdit/CopySampleLoop"));
577            item->set_tooltip_text(_("Used when dragging a sample to a region's sample reference field. You may disable this for example if you want to replace an existing sample in a region with a new sample, but don't want that the region's current loop informations to be altered by this action."));
578        }
579        {
580            Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
581                uiManager->get_widget("/MenuBar/MenuSettings/WarnUserOnExtensions"));
582            item->set_tooltip_text(_("If checked, a warning will be shown whenever you try to use a feature which is based on a LinuxSampler extension ontop of the original gig format, which would not work with the Gigasampler/GigaStudio application."));
583        }
584        {
585            Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
586                uiManager->get_widget("/MenuBar/MenuSettings/SyncSamplerInstrumentSelection"));
587            item->set_tooltip_text(_("If checked, the sampler's current instrument will automatically be switched whenever another instrument was selected in gigedit (only available in live-mode)."));
588        }
589        {
590            Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
591                uiManager->get_widget("/MenuBar/MenuSettings/MoveRootNoteWithRegionMoved"));
592            item->set_tooltip_text(_("If checked, and when a region is moved by dragging it around on the virtual keyboard, the keybord position dependent pitch will move exactly with the amount of semi tones the region was moved around."));
593        }
594        {
595            Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
596                uiManager->get_widget("/MenuBar/MenuSample/RemoveUnusedSamples"));
597            item->set_tooltip_text(_("Removes all samples that are not referenced by any instrument (i.e. red ones)."));
598            // copy tooltip to popup menu
599            Gtk::MenuItem* item2 = dynamic_cast<Gtk::MenuItem*>(
600                uiManager->get_widget("/SamplePopupMenu/RemoveUnusedSamples"));
601            item2->set_tooltip_text(item->get_tooltip_text());
602        }
603        {
604            Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
605                uiManager->get_widget("/MenuBar/MenuView/RefreshAll"));
606            item->set_tooltip_text(_("Reloads the currently open gig file and updates the entire graphical user interface."));
607        }
608        {
609            Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
610                uiManager->get_widget("/MenuBar/MenuView/AutoRestoreWinDim"));
611            item->set_tooltip_text(_("If checked, size and position of all windows will be saved and automatically restored next time."));
612        }
613        {
614            Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
615                uiManager->get_widget("/MenuBar/MenuTools/CombineInstruments"));
616            item->set_tooltip_text(_("Create combi sounds out of individual sounds of this .gig file."));
617        }
618        {
619            Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
620                uiManager->get_widget("/MenuBar/MenuTools/MergeFiles"));
621            item->set_tooltip_text(_("Add instruments and samples of other .gig files to this .gig file."));
622        }
623    
624    
625        instrument_menu = static_cast<Gtk::MenuItem*>(
626            uiManager->get_widget("/MenuBar/MenuInstrument/AllInstruments"))->get_submenu();
627    
628      Gtk::Widget* menuBar = uiManager->get_widget("/MenuBar");      Gtk::Widget* menuBar = uiManager->get_widget("/MenuBar");
629      m_VBox.pack_start(*menuBar, Gtk::PACK_SHRINK);      m_VBox.pack_start(*menuBar, Gtk::PACK_SHRINK);
# Line 256  MainWindow::MainWindow() : Line 633  MainWindow::MainWindow() :
633      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
634      m_VBox.pack_start(m_StatusBar, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_StatusBar, Gtk::PACK_SHRINK);
635    
636        set_file_is_shared(false);
637    
638      // Status Bar:      // Status Bar:
639      m_StatusBar.pack_start(m_AttachedStateLabel, Gtk::PACK_SHRINK);      m_StatusBar.pack_start(m_AttachedStateLabel, Gtk::PACK_SHRINK);
640      m_StatusBar.pack_start(m_AttachedStateImage, Gtk::PACK_SHRINK);      m_StatusBar.pack_start(m_AttachedStateImage, Gtk::PACK_SHRINK);
# Line 270  MainWindow::MainWindow() : Line 649  MainWindow::MainWindow() :
649      // Create the Tree model:      // Create the Tree model:
650      m_refTreeModel = Gtk::ListStore::create(m_Columns);      m_refTreeModel = Gtk::ListStore::create(m_Columns);
651      m_TreeView.set_model(m_refTreeModel);      m_TreeView.set_model(m_refTreeModel);
652      m_refTreeModel->signal_row_changed().connect(      m_TreeView.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
653        m_TreeView.set_tooltip_text(_("Right click here for actions on instruments & MIDI Rules. Drag & drop to change the order of instruments."));
654        instrument_name_connection = m_refTreeModel->signal_row_changed().connect(
655          sigc::mem_fun(*this, &MainWindow::instrument_name_changed)          sigc::mem_fun(*this, &MainWindow::instrument_name_changed)
656      );      );
657    
658      // Add the TreeView's view columns:      // Add the TreeView's view columns:
659      m_TreeView.append_column_editable("Instrument", m_Columns.m_col_name);      m_TreeView.append_column(_("Nr"), m_Columns.m_col_nr);
660      m_TreeView.set_headers_visible(false);      m_TreeView.append_column_editable(_("Instrument"), m_Columns.m_col_name);
661        m_TreeView.append_column(_("Scripts"), m_Columns.m_col_scripts);
662        m_TreeView.set_headers_visible(true);
663        
664        // establish drag&drop within the instrument tree view, allowing to reorder
665        // the sequence of instruments within the gig file
666        {
667            std::vector<Gtk::TargetEntry> drag_target_instrument;
668            drag_target_instrument.push_back(Gtk::TargetEntry("gig::Instrument"));
669            m_TreeView.drag_source_set(drag_target_instrument);
670            m_TreeView.drag_dest_set(drag_target_instrument);
671            m_TreeView.signal_drag_begin().connect(
672                sigc::mem_fun(*this, &MainWindow::on_instruments_treeview_drag_begin)
673            );
674            m_TreeView.signal_drag_data_get().connect(
675                sigc::mem_fun(*this, &MainWindow::on_instruments_treeview_drag_data_get)
676            );
677            m_TreeView.signal_drag_data_received().connect(
678                sigc::mem_fun(*this, &MainWindow::on_instruments_treeview_drop_drag_data_received)
679            );
680        }
681    
682      // create samples treeview (including its data model)      // create samples treeview (including its data model)
683      m_refSamplesTreeModel = SamplesTreeStore::create(m_SamplesModel);      m_refSamplesTreeModel = SamplesTreeStore::create(m_SamplesModel);
684      m_TreeViewSamples.set_model(m_refSamplesTreeModel);      m_TreeViewSamples.set_model(m_refSamplesTreeModel);
685        m_TreeViewSamples.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
686        m_TreeViewSamples.set_tooltip_text(_("To actually use a sample, drag it from this list view to \"Sample\" -> \"Sample:\" on the region's settings pane on the right.\n\nRight click here for more actions on samples."));
687      // m_TreeViewSamples.set_reorderable();      // m_TreeViewSamples.set_reorderable();
688      m_TreeViewSamples.append_column_editable("Samples", m_SamplesModel.m_col_name);      m_TreeViewSamples.append_column_editable(_("Name"), m_SamplesModel.m_col_name);
689      m_TreeViewSamples.set_headers_visible(false);      m_TreeViewSamples.append_column(_("Referenced"), m_SamplesModel.m_col_refcount);
690        {
691            Gtk::TreeViewColumn* column = m_TreeViewSamples.get_column(0);
692            Gtk::CellRendererText* cellrenderer =
693                dynamic_cast<Gtk::CellRendererText*>(column->get_first_cell());
694            column->add_attribute(
695                cellrenderer->property_foreground(), m_SamplesModel.m_color
696            );
697        }
698        {
699            Gtk::TreeViewColumn* column = m_TreeViewSamples.get_column(1);
700            Gtk::CellRendererText* cellrenderer =
701                dynamic_cast<Gtk::CellRendererText*>(column->get_first_cell());
702            column->add_attribute(
703                cellrenderer->property_foreground(), m_SamplesModel.m_color
704            );
705        }
706        m_TreeViewSamples.set_headers_visible(true);
707      m_TreeViewSamples.signal_button_press_event().connect_notify(      m_TreeViewSamples.signal_button_press_event().connect_notify(
708          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_button_release)          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_button_release)
709      );      );
# Line 291  MainWindow::MainWindow() : Line 711  MainWindow::MainWindow() :
711          sigc::mem_fun(*this, &MainWindow::sample_name_changed)          sigc::mem_fun(*this, &MainWindow::sample_name_changed)
712      );      );
713    
714        // create scripts treeview (including its data model)
715        m_refScriptsTreeModel = ScriptsTreeStore::create(m_ScriptsModel);
716        m_TreeViewScripts.set_model(m_refScriptsTreeModel);
717        m_TreeViewScripts.set_tooltip_text(_(
718            "Use CTRL + double click for editing a script."
719            "\n\n"
720            "Note: instrument scripts are a LinuxSampler extension of the gig "
721            "format. This feature will not work with the GigaStudio software!"
722        ));
723        // m_TreeViewScripts.set_reorderable();
724        m_TreeViewScripts.append_column_editable("Samples", m_ScriptsModel.m_col_name);
725        m_TreeViewScripts.set_headers_visible(false);
726        m_TreeViewScripts.signal_button_press_event().connect_notify(
727            sigc::mem_fun(*this, &MainWindow::on_script_treeview_button_release)
728        );
729        //FIXME: why the heck does this double click signal_row_activated() only fire while CTRL key is pressed ?
730        m_TreeViewScripts.signal_row_activated().connect(
731            sigc::mem_fun(*this, &MainWindow::script_double_clicked)
732        );
733        m_refScriptsTreeModel->signal_row_changed().connect(
734            sigc::mem_fun(*this, &MainWindow::script_name_changed)
735        );
736    
737        // establish drag&drop between scripts tree view and ScriptSlots window
738        std::vector<Gtk::TargetEntry> drag_target_gig_script;
739        drag_target_gig_script.push_back(Gtk::TargetEntry("gig::Script"));
740        m_TreeViewScripts.drag_source_set(drag_target_gig_script);
741        m_TreeViewScripts.signal_drag_begin().connect(
742            sigc::mem_fun(*this, &MainWindow::on_scripts_treeview_drag_begin)
743        );
744        m_TreeViewScripts.signal_drag_data_get().connect(
745            sigc::mem_fun(*this, &MainWindow::on_scripts_treeview_drag_data_get)
746        );
747    
748      // establish drag&drop between samples tree view and dimension region 'Sample' text entry      // establish drag&drop between samples tree view and dimension region 'Sample' text entry
749      std::list<Gtk::TargetEntry> drag_target_gig_sample;      std::vector<Gtk::TargetEntry> drag_target_gig_sample;
750      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );      drag_target_gig_sample.push_back(Gtk::TargetEntry("gig::Sample"));
751      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
752      m_TreeViewSamples.signal_drag_begin().connect(      m_TreeViewSamples.signal_drag_begin().connect(
753          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)
# Line 309  MainWindow::MainWindow() : Line 763  MainWindow::MainWindow() :
763          sigc::hide(sigc::mem_fun(*this, &MainWindow::file_changed)));          sigc::hide(sigc::mem_fun(*this, &MainWindow::file_changed)));
764      m_RegionChooser.signal_instrument_changed().connect(      m_RegionChooser.signal_instrument_changed().connect(
765          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
766        m_RegionChooser.signal_instrument_changed().connect(
767            sigc::mem_fun(*this, &MainWindow::region_changed));
768      m_DimRegionChooser.signal_region_changed().connect(      m_DimRegionChooser.signal_region_changed().connect(
769          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
770      instrumentProps.signal_instrument_changed().connect(      instrumentProps.signal_changed().connect(
771            sigc::mem_fun(*this, &MainWindow::file_changed));
772        propDialog.signal_changed().connect(
773          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
774      propDialog.signal_info_changed().connect(      midiRules.signal_changed().connect(
775          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
776    
777      dimreg_edit.signal_dimreg_to_be_changed().connect(      dimreg_edit.signal_dimreg_to_be_changed().connect(
# Line 322  MainWindow::MainWindow() : Line 780  MainWindow::MainWindow() :
780          dimreg_changed_signal.make_slot());          dimreg_changed_signal.make_slot());
781      dimreg_edit.signal_sample_ref_changed().connect(      dimreg_edit.signal_sample_ref_changed().connect(
782          sample_ref_changed_signal.make_slot());          sample_ref_changed_signal.make_slot());
783        sample_ref_changed_signal.connect(
784            sigc::mem_fun(*this, &MainWindow::on_sample_ref_changed)
785        );
786        samples_to_be_removed_signal.connect(
787            sigc::mem_fun(*this, &MainWindow::on_samples_to_be_removed)
788        );
789    
790        dimreg_edit.signal_select_sample().connect(
791            sigc::mem_fun(*this, &MainWindow::select_sample)
792        );
793    
794      m_RegionChooser.signal_instrument_struct_to_be_changed().connect(      m_RegionChooser.signal_instrument_struct_to_be_changed().connect(
795          sigc::hide(          sigc::hide(
# Line 358  MainWindow::MainWindow() : Line 826  MainWindow::MainWindow() :
826    
827      file = 0;      file = 0;
828      file_is_changed = false;      file_is_changed = false;
     set_file_is_shared(false);  
829    
830      show_all_children();      show_all_children();
831    
832      // start with a new gig file by default      // start with a new gig file by default
833      on_action_file_new();      on_action_file_new();
834    
835        // select 'Instruments' tab by default
836        // (gtk allows this only if the tab childs are visible, thats why it's here)
837        m_TreeViewNotebook.set_current_page(1);
838    
839        Gtk::Clipboard::get()->signal_owner_change().connect(
840            sigc::mem_fun(*this, &MainWindow::on_clipboard_owner_change)
841        );
842        updateClipboardPasteAvailable();
843        updateClipboardCopyAvailable();
844    
845        // setup macros and their keyboard accelerators
846        {
847            Gtk::Menu* menuMacro = dynamic_cast<Gtk::MenuItem*>(
848                uiManager->get_widget("/MenuBar/MenuMacro")
849            )->get_submenu();
850    
851            const Gdk::ModifierType primaryModifierKey =
852    #if defined(__APPLE__)
853                Gdk::META_MASK; // Cmd key on Mac
854    #else
855                Gdk::CONTROL_MASK; // Ctrl key on all other OSs
856    #endif
857    
858            const Gdk::ModifierType noModifier = (Gdk::ModifierType)0;
859            Gtk::AccelMap::add_entry("<Macros>/macro_0", GDK_KEY_F1, noModifier);
860            Gtk::AccelMap::add_entry("<Macros>/macro_1", GDK_KEY_F2, noModifier);
861            Gtk::AccelMap::add_entry("<Macros>/macro_2", GDK_KEY_F3, noModifier);
862            Gtk::AccelMap::add_entry("<Macros>/macro_3", GDK_KEY_F4, noModifier);
863            Gtk::AccelMap::add_entry("<Macros>/macro_4", GDK_KEY_F5, noModifier);
864            Gtk::AccelMap::add_entry("<Macros>/macro_5", GDK_KEY_F6, noModifier);
865            Gtk::AccelMap::add_entry("<Macros>/macro_6", GDK_KEY_F7, noModifier);
866            Gtk::AccelMap::add_entry("<Macros>/macro_7", GDK_KEY_F8, noModifier);
867            Gtk::AccelMap::add_entry("<Macros>/macro_8", GDK_KEY_F9, noModifier);
868            Gtk::AccelMap::add_entry("<Macros>/macro_9", GDK_KEY_F10, noModifier);
869            Gtk::AccelMap::add_entry("<Macros>/macro_10", GDK_KEY_F11, noModifier);
870            Gtk::AccelMap::add_entry("<Macros>/macro_11", GDK_KEY_F12, noModifier);
871            Gtk::AccelMap::add_entry("<Macros>/SetupMacros", 'm', primaryModifierKey);
872    
873            Glib::RefPtr<Gtk::AccelGroup> accelGroup = this->get_accel_group();
874            menuMacro->set_accel_group(accelGroup);
875    
876            updateMacroMenu();
877        }
878  }  }
879    
880  MainWindow::~MainWindow()  MainWindow::~MainWindow()
881  {  {
882  }  }
883    
884    void MainWindow::updateMacroMenu() {
885        Gtk::Menu* menuMacro = dynamic_cast<Gtk::MenuItem*>(
886            uiManager->get_widget("/MenuBar/MenuMacro")
887        )->get_submenu();
888    
889        // remove all entries from "Macro" menu
890        {
891            const std::vector<Gtk::Widget*> children = menuMacro->get_children();
892            for (int i = 0; i < children.size(); ++i) {
893                Gtk::Widget* child = children[i];
894                menuMacro->remove(*child);
895                delete child;
896            }
897        }
898    
899        // (re)load all macros from config file
900        try {
901            Settings::singleton()->loadMacros(m_macros);
902        } catch (Serialization::Exception e) {
903            std::cerr << "Exception while loading macros: " << e.Message << std::endl;
904        } catch (...) {
905            std::cerr << "Unknown exception while loading macros!" << std::endl;
906        }
907    
908        // add all configured macros as menu items to the "Macro" menu
909        for (int iMacro = 0; iMacro < m_macros.size(); ++iMacro) {
910            const Serialization::Archive& macro = m_macros[iMacro];
911            std::string name =
912                macro.name().empty() ?
913                    (std::string(_("Unnamed Macro")) + " " + ToString(iMacro+1)) : macro.name();
914            Gtk::MenuItem* item = new Gtk::MenuItem(name);
915            item->signal_activate().connect(
916                sigc::bind(
917                    sigc::mem_fun(*this, &MainWindow::onMacroSelected), iMacro
918                )
919            );
920            menuMacro->append(*item);
921            item->set_accel_path("<Macros>/macro_" + ToString(iMacro));
922            Glib::ustring comment = macro.comment();
923            if (!comment.empty())
924                item->set_tooltip_text(comment);
925        }
926        // if there are no macros configured at all, then show a dummy entry instead
927        if (m_macros.empty()) {
928            Gtk::MenuItem* item = new Gtk::MenuItem(_("No Macros"));
929            item->set_sensitive(false);
930            menuMacro->append(*item);
931        }
932    
933        // add separator line to menu
934        menuMacro->append(*new Gtk::SeparatorMenuItem);
935    
936        {
937            Gtk::MenuItem* item = new Gtk::MenuItem(_("Setup Macros ..."));
938            item->signal_activate().connect(
939                sigc::mem_fun(*this, &MainWindow::setupMacros)
940            );
941            menuMacro->append(*item);
942            item->set_accel_path("<Macros>/SetupMacros");
943        }
944    
945        menuMacro->show_all_children();
946    }
947    
948    void MainWindow::onMacroSelected(int iMacro) {
949        printf("onMacroSelected(%d)\n", iMacro);
950        if (iMacro < 0 || iMacro >= m_macros.size()) return;
951        Glib::ustring errorText;
952        try {
953            applyMacro(m_macros[iMacro]);
954        } catch (Serialization::Exception e) {
955            errorText = e.Message;
956        } catch (...) {
957            errorText = _("Unknown exception while applying macro");
958        }
959        if (!errorText.empty()) {
960            Glib::ustring txt = _("Applying macro failed:\n") + errorText;
961            Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
962            msg.run();
963        }
964    }
965    
966    void MainWindow::setupMacros() {
967        MacrosSetup* setup = new MacrosSetup();
968        gig::DimensionRegion* pDimRgn = m_DimRegionChooser.get_main_dimregion();
969        setup->setMacros(m_macros, &m_serializationArchive, pDimRgn);
970        setup->signal_macros_changed().connect(
971            sigc::mem_fun(*this, &MainWindow::onMacrosSetupChanged)
972        );
973        setup->show();
974    }
975    
976    void MainWindow::onMacrosSetupChanged(const std::vector<Serialization::Archive>& macros) {
977        m_macros = macros;
978        Settings::singleton()->saveMacros(m_macros);
979        updateMacroMenu();
980    }
981    
982  bool MainWindow::on_delete_event(GdkEventAny* event)  bool MainWindow::on_delete_event(GdkEventAny* event)
983  {  {
984      return !file_is_shared && file_is_changed && !close_confirmation_dialog();      return !file_is_shared && file_is_changed && !close_confirmation_dialog();
# Line 389  void MainWindow::region_changed() Line 998  void MainWindow::region_changed()
998  gig::Instrument* MainWindow::get_instrument()  gig::Instrument* MainWindow::get_instrument()
999  {  {
1000      gig::Instrument* instrument = 0;      gig::Instrument* instrument = 0;
1001      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      std::vector<Gtk::TreeModel::Path> rows = m_TreeView.get_selection()->get_selected_rows();
1002        if (rows.empty()) return NULL;
1003      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      Gtk::TreeModel::const_iterator it = m_refTreeModel->get_iter(rows[0]);
1004      if (it) {      if (it) {
1005          Gtk::TreeModel::Row row = *it;          Gtk::TreeModel::Row row = *it;
1006          instrument = row[m_Columns.m_col_instr];          instrument = row[m_Columns.m_col_instr];
# Line 434  void MainWindow::update_dimregs() Line 1043  void MainWindow::update_dimregs()
1043              add_region_to_dimregs(region, stereo, all_dimregs);              add_region_to_dimregs(region, stereo, all_dimregs);
1044          }          }
1045      }      }
1046    
1047        m_RegionChooser.setModifyAllRegions(all_regions);
1048        m_DimRegionChooser.setModifyAllRegions(all_regions);
1049        m_DimRegionChooser.setModifyAllDimensionRegions(all_dimregs);
1050        m_DimRegionChooser.setModifyBothChannels(stereo);
1051    
1052        updateClipboardCopyAvailable();
1053  }  }
1054    
1055  void MainWindow::dimreg_all_dimregs_toggled()  void MainWindow::dimreg_all_dimregs_toggled()
# Line 445  void MainWindow::dimreg_all_dimregs_togg Line 1061  void MainWindow::dimreg_all_dimregs_togg
1061  void MainWindow::dimreg_changed()  void MainWindow::dimreg_changed()
1062  {  {
1063      update_dimregs();      update_dimregs();
1064      dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());      dimreg_edit.set_dim_region(m_DimRegionChooser.get_main_dimregion());
1065  }  }
1066    
1067  void MainWindow::on_sel_change()  void MainWindow::on_sel_change()
1068  {  {
1069        // select item in instrument menu
1070        std::vector<Gtk::TreeModel::Path> rows = m_TreeView.get_selection()->get_selected_rows();
1071        if (!rows.empty()) {
1072            Gtk::TreeModel::iterator it = m_refTreeModel->get_iter(rows[0]);
1073            if (it) {
1074                Gtk::TreePath path(it);
1075                int index = path[0];
1076                const std::vector<Gtk::Widget*> children =
1077                    instrument_menu->get_children();
1078                static_cast<Gtk::RadioMenuItem*>(children[index])->set_active();
1079            }
1080        }
1081    
1082      m_RegionChooser.set_instrument(get_instrument());      m_RegionChooser.set_instrument(get_instrument());
1083    
1084        if (Settings::singleton()->syncSamplerInstrumentSelection) {
1085            switch_sampler_instrument_signal.emit(get_instrument());
1086        }
1087  }  }
1088    
1089  void loader_progress_callback(gig::progress_t* progress)  void loader_progress_callback(gig::progress_t* progress)
# Line 462  void loader_progress_callback(gig::progr Line 1095  void loader_progress_callback(gig::progr
1095  void Loader::progress_callback(float fraction)  void Loader::progress_callback(float fraction)
1096  {  {
1097      {      {
1098          Glib::Mutex::Lock lock(progressMutex);          Glib::Threads::Mutex::Lock lock(progressMutex);
1099          progress = fraction;          progress = fraction;
1100      }      }
1101      progress_dispatcher();      progress_dispatcher();
1102  }  }
1103    
1104    #if defined(WIN32) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
1105    // make sure stack is 16-byte aligned for SSE instructions
1106    __attribute__((force_align_arg_pointer))
1107    #endif
1108  void Loader::thread_function()  void Loader::thread_function()
1109  {  {
1110      printf("thread_function self=%x\n", Glib::Thread::self());      printf("thread_function self=%p\n",
1111      printf("Start %s\n", filename);             static_cast<void*>(Glib::Threads::Thread::self()));
1112      RIFF::File* riff = new RIFF::File(filename);      printf("Start %s\n", filename.c_str());
1113      gig = new gig::File(riff);      try {
1114      gig::progress_t progress;          RIFF::File* riff = new RIFF::File(filename);
1115      progress.callback = loader_progress_callback;          gig = new gig::File(riff);
1116      progress.custom = this;          gig::progress_t progress;
1117            progress.callback = loader_progress_callback;
1118      gig->GetInstrument(0, &progress);          progress.custom = this;
1119      printf("End\n");  
1120      finished_dispatcher();          gig->GetInstrument(0, &progress);
1121            printf("End\n");
1122            finished_dispatcher();
1123        } catch (RIFF::Exception e) {
1124            error_message = e.Message;
1125            error_dispatcher.emit();
1126        } catch (...) {
1127            error_message = _("Unknown exception occurred");
1128            error_dispatcher.emit();
1129        }
1130  }  }
1131    
1132  Loader::Loader(const char* filename)  Loader::Loader(const char* filename)
1133      : filename(filename), thread(0)      : filename(filename), gig(0), thread(0), progress(0.f)
1134  {  {
1135  }  }
1136    
1137  void Loader::launch()  void Loader::launch()
1138  {  {
1139    #ifdef OLD_THREADS
1140      thread = Glib::Thread::create(sigc::mem_fun(*this, &Loader::thread_function), true);      thread = Glib::Thread::create(sigc::mem_fun(*this, &Loader::thread_function), true);
1141      printf("launch thread=%x\n", thread);  #else
1142        thread = Glib::Threads::Thread::create(sigc::mem_fun(*this, &Loader::thread_function));
1143    #endif
1144        printf("launch thread=%p\n", static_cast<void*>(thread));
1145  }  }
1146    
1147  float Loader::get_progress()  float Loader::get_progress()
1148  {  {
1149      float res;      float res;
1150      {      {
1151          Glib::Mutex::Lock lock(progressMutex);          Glib::Threads::Mutex::Lock lock(progressMutex);
1152          res = progress;          res = progress;
1153      }      }
1154      return res;      return res;
# Line 514  Glib::Dispatcher& Loader::signal_finishe Line 1164  Glib::Dispatcher& Loader::signal_finishe
1164      return finished_dispatcher;      return finished_dispatcher;
1165  }  }
1166    
1167  LoadDialog::LoadDialog(const Glib::ustring& title, Gtk::Window& parent)  Glib::Dispatcher& Loader::signal_error()
1168    {
1169        return error_dispatcher;
1170    }
1171    
1172    void saver_progress_callback(gig::progress_t* progress)
1173    {
1174        Saver* saver = static_cast<Saver*>(progress->custom);
1175        saver->progress_callback(progress->factor);
1176    }
1177    
1178    void Saver::progress_callback(float fraction)
1179    {
1180        {
1181            Glib::Threads::Mutex::Lock lock(progressMutex);
1182            progress = fraction;
1183        }
1184        progress_dispatcher.emit();
1185    }
1186    
1187    #if defined(WIN32) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
1188    // make sure stack is 16-byte aligned for SSE instructions
1189    __attribute__((force_align_arg_pointer))
1190    #endif
1191    void Saver::thread_function()
1192    {
1193        printf("thread_function self=%p\n",
1194               static_cast<void*>(Glib::Threads::Thread::self()));
1195        printf("Start %s\n", filename.c_str());
1196        try {
1197            gig::progress_t progress;
1198            progress.callback = saver_progress_callback;
1199            progress.custom = this;
1200    
1201            // if no filename was provided, that means "save", if filename was provided means "save as"
1202            if (filename.empty()) {
1203                if (!Settings::singleton()->saveWithTemporaryFile) {
1204                    // save directly over the existing .gig file
1205                    // (requires less disk space than solution below
1206                    // but may be slower)
1207                    gig->Save(&progress);
1208                } else {
1209                    // save the file as separate temporary file first,
1210                    // then move the saved file over the old file
1211                    // (may result in performance speedup during save)
1212                    gig::String tmpname = filename + ".TMP";
1213                    gig->Save(tmpname, &progress);
1214                    #if defined(WIN32)
1215                    if (!DeleteFile(filename.c_str())) {
1216                        throw RIFF::Exception("Could not replace original file with temporary file (unable to remove original file).");
1217                    }
1218                    #else // POSIX ...
1219                    if (unlink(filename.c_str())) {
1220                        throw RIFF::Exception("Could not replace original file with temporary file (unable to remove original file): " + gig::String(strerror(errno)));
1221                    }
1222                    #endif
1223                    if (rename(tmpname.c_str(), filename.c_str())) {
1224                        #if defined(WIN32)
1225                        throw RIFF::Exception("Could not replace original file with temporary file (unable to rename temp file).");
1226                        #else
1227                        throw RIFF::Exception("Could not replace original file with temporary file (unable to rename temp file): " + gig::String(strerror(errno)));
1228                        #endif
1229                    }
1230                }
1231            } else {
1232                gig->Save(filename, &progress);
1233            }
1234    
1235            printf("End\n");
1236            finished_dispatcher.emit();
1237        } catch (RIFF::Exception e) {
1238            error_message = e.Message;
1239            error_dispatcher.emit();
1240        } catch (...) {
1241            error_message = _("Unknown exception occurred");
1242            error_dispatcher.emit();
1243        }
1244    }
1245    
1246    Saver::Saver(gig::File* file, Glib::ustring filename)
1247        : gig(file), filename(filename), thread(0), progress(0.f)
1248    {
1249    }
1250    
1251    void Saver::launch()
1252    {
1253    #ifdef OLD_THREADS
1254        thread = Glib::Thread::create(sigc::mem_fun(*this, &Saver::thread_function), true);
1255    #else
1256        thread = Glib::Threads::Thread::create(sigc::mem_fun(*this, &Saver::thread_function));
1257    #endif
1258        printf("launch thread=%p\n", static_cast<void*>(thread));
1259    }
1260    
1261    float Saver::get_progress()
1262    {
1263        float res;
1264        {
1265            Glib::Threads::Mutex::Lock lock(progressMutex);
1266            res = progress;
1267        }
1268        return res;
1269    }
1270    
1271    Glib::Dispatcher& Saver::signal_progress()
1272    {
1273        return progress_dispatcher;
1274    }
1275    
1276    Glib::Dispatcher& Saver::signal_finished()
1277    {
1278        return finished_dispatcher;
1279    }
1280    
1281    Glib::Dispatcher& Saver::signal_error()
1282    {
1283        return error_dispatcher;
1284    }
1285    
1286    ProgressDialog::ProgressDialog(const Glib::ustring& title, Gtk::Window& parent)
1287      : Gtk::Dialog(title, parent, true)      : Gtk::Dialog(title, parent, true)
1288  {  {
1289      get_vbox()->pack_start(progressBar);      get_vbox()->pack_start(progressBar);
1290      show_all_children();      show_all_children();
1291        resize(600,50);
1292  }  }
1293    
1294  // Clear all GUI elements / controls. This method is typically called  // Clear all GUI elements / controls. This method is typically called
1295  // before a new .gig file is to be created or to be loaded.  // before a new .gig file is to be created or to be loaded.
1296  void MainWindow::__clear() {  void MainWindow::__clear() {
     // remove all entries from "Instrument" menu  
     Gtk::MenuItem* instrument_menu =  
         dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));  
     instrument_menu->hide();  
     for (int i = 0; i < instrument_menu->get_submenu()->items().size(); i++) {  
         delete &instrument_menu->get_submenu()->items()[i];  
     }  
     instrument_menu->get_submenu()->items().clear();  
1297      // forget all samples that ought to be imported      // forget all samples that ought to be imported
1298      m_SampleImportQueue.clear();      m_SampleImportQueue.clear();
1299      // clear the samples and instruments tree views      // clear the samples and instruments tree views
1300      m_refTreeModel->clear();      m_refTreeModel->clear();
1301      m_refSamplesTreeModel->clear();      m_refSamplesTreeModel->clear();
1302        m_refScriptsTreeModel->clear();
1303        // remove all entries from "Instrument" menu
1304        while (!instrument_menu->get_children().empty()) {
1305            remove_instrument_from_menu(0);
1306        }
1307      // free libgig's gig::File instance      // free libgig's gig::File instance
1308      if (file && !file_is_shared) delete file;      if (file && !file_is_shared) delete file;
1309      file = NULL;      file = NULL;
1310      set_file_is_shared(false);      set_file_is_shared(false);
1311  }  }
1312    
1313    void MainWindow::__refreshEntireGUI() {
1314        // clear the samples and instruments tree views
1315        m_refTreeModel->clear();
1316        m_refSamplesTreeModel->clear();
1317        m_refScriptsTreeModel->clear();
1318        // remove all entries from "Instrument" menu
1319        while (!instrument_menu->get_children().empty()) {
1320            remove_instrument_from_menu(0);
1321        }
1322    
1323        if (!this->file) return;
1324    
1325        load_gig(
1326            this->file, this->file->pInfo->Name.c_str(), this->file_is_shared
1327        );
1328    }
1329    
1330  void MainWindow::on_action_file_new()  void MainWindow::on_action_file_new()
1331  {  {
1332      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
# Line 555  void MainWindow::on_action_file_new() Line 1339  void MainWindow::on_action_file_new()
1339      gig::File* pFile = new gig::File;      gig::File* pFile = new gig::File;
1340      // already add one new instrument by default      // already add one new instrument by default
1341      gig::Instrument* pInstrument = pFile->AddInstrument();      gig::Instrument* pInstrument = pFile->AddInstrument();
1342      pInstrument->pInfo->Name = _("Unnamed Instrument");      pInstrument->pInfo->Name = gig_from_utf8(_("Unnamed Instrument"));
1343      // update GUI with that new gig::File      // update GUI with that new gig::File
1344      load_gig(pFile, 0 /*no file name yet*/);      load_gig(pFile, 0 /*no file name yet*/);
1345  }  }
# Line 573  bool MainWindow::close_confirmation_dial Line 1357  bool MainWindow::close_confirmation_dial
1357      dialog.set_default_response(Gtk::RESPONSE_YES);      dialog.set_default_response(Gtk::RESPONSE_YES);
1358      int response = dialog.run();      int response = dialog.run();
1359      dialog.hide();      dialog.hide();
1360      if (response == Gtk::RESPONSE_YES) return file_save();  
1361      return response != Gtk::RESPONSE_CANCEL;      // user decided to exit app without saving
1362        if (response == Gtk::RESPONSE_NO) return true;
1363    
1364        // user cancelled dialog, thus don't close app
1365        if (response == Gtk::RESPONSE_CANCEL) return false;
1366    
1367        // TODO: the following return valid is disabled and hard coded instead for
1368        // now, due to the fact that saving with progress bar is now implemented
1369        // asynchronously, as a result the app does not close automatically anymore
1370        // after saving the file has completed
1371        //
1372        //   if (response == Gtk::RESPONSE_YES) return file_save();
1373        //   return response != Gtk::RESPONSE_CANCEL;
1374        //
1375        if (response == Gtk::RESPONSE_YES) file_save();
1376        return false; // always prevent closing the app for now (see comment above)
1377  }  }
1378    
1379  bool MainWindow::leaving_shared_mode_dialog() {  bool MainWindow::leaving_shared_mode_dialog() {
# Line 602  void MainWindow::on_action_file_open() Line 1401  void MainWindow::on_action_file_open()
1401      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1402      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1403      dialog.set_default_response(Gtk::RESPONSE_OK);      dialog.set_default_response(Gtk::RESPONSE_OK);
1404    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1405      Gtk::FileFilter filter;      Gtk::FileFilter filter;
1406      filter.add_pattern("*.gig");      filter.add_pattern("*.gig");
1407    #else
1408        Glib::RefPtr<Gtk::FileFilter> filter = Gtk::FileFilter::create();
1409        filter->add_pattern("*.gig");
1410    #endif
1411      dialog.set_filter(filter);      dialog.set_filter(filter);
1412      if (current_gig_dir != "") {      if (current_gig_dir != "") {
1413          dialog.set_current_folder(current_gig_dir);          dialog.set_current_folder(current_gig_dir);
# Line 611  void MainWindow::on_action_file_open() Line 1415  void MainWindow::on_action_file_open()
1415      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
1416          std::string filename = dialog.get_filename();          std::string filename = dialog.get_filename();
1417          printf("filename=%s\n", filename.c_str());          printf("filename=%s\n", filename.c_str());
1418          printf("on_action_file_open self=%x\n", Glib::Thread::self());          printf("on_action_file_open self=%p\n",
1419                   static_cast<void*>(Glib::Threads::Thread::self()));
1420          load_file(filename.c_str());          load_file(filename.c_str());
1421          current_gig_dir = Glib::path_get_dirname(filename);          current_gig_dir = Glib::path_get_dirname(filename);
1422      }      }
# Line 620  void MainWindow::on_action_file_open() Line 1425  void MainWindow::on_action_file_open()
1425  void MainWindow::load_file(const char* name)  void MainWindow::load_file(const char* name)
1426  {  {
1427      __clear();      __clear();
1428      load_dialog = new LoadDialog(_("Loading..."), *this);  
1429      load_dialog->show_all();      progress_dialog = new ProgressDialog( //FIXME: memory leak!
1430      loader = new Loader(strdup(name));          _("Loading") +  Glib::ustring(" '") +
1431            Glib::filename_display_basename(name) + "' ...",
1432            *this
1433        );
1434        progress_dialog->show_all();
1435        loader = new Loader(name); //FIXME: memory leak!
1436      loader->signal_progress().connect(      loader->signal_progress().connect(
1437          sigc::mem_fun(*this, &MainWindow::on_loader_progress));          sigc::mem_fun(*this, &MainWindow::on_loader_progress));
1438      loader->signal_finished().connect(      loader->signal_finished().connect(
1439          sigc::mem_fun(*this, &MainWindow::on_loader_finished));          sigc::mem_fun(*this, &MainWindow::on_loader_finished));
1440        loader->signal_error().connect(
1441            sigc::mem_fun(*this, &MainWindow::on_loader_error));
1442      loader->launch();      loader->launch();
1443  }  }
1444    
# Line 642  void MainWindow::load_instrument(gig::In Line 1454  void MainWindow::load_instrument(gig::In
1454      // load the instrument      // load the instrument
1455      gig::File* pFile = (gig::File*) instr->GetParent();      gig::File* pFile = (gig::File*) instr->GetParent();
1456      load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);      load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);
1457      //TODO: automatically select the given instrument      // automatically select the given instrument
1458        int i = 0;
1459        for (gig::Instrument* instrument = pFile->GetFirstInstrument(); instrument;
1460             instrument = pFile->GetNextInstrument(), ++i)
1461        {
1462            if (instrument == instr) {
1463                // select item in "instruments" tree view
1464                m_TreeView.get_selection()->select(Gtk::TreePath(ToString(i)));
1465                // make sure the selected item in the "instruments" tree view is
1466                // visible (scroll to it)
1467                m_TreeView.scroll_to_row(Gtk::TreePath(ToString(i)));
1468                // select item in instrument menu
1469                {
1470                    const std::vector<Gtk::Widget*> children =
1471                        instrument_menu->get_children();
1472                    static_cast<Gtk::RadioMenuItem*>(children[i])->set_active();
1473                }
1474                // update region chooser and dimension region chooser
1475                m_RegionChooser.set_instrument(instr);
1476                break;
1477            }
1478        }
1479  }  }
1480    
1481  void MainWindow::on_loader_progress()  void MainWindow::on_loader_progress()
1482  {  {
1483      load_dialog->set_fraction(loader->get_progress());      progress_dialog->set_fraction(loader->get_progress());
1484  }  }
1485    
1486  void MainWindow::on_loader_finished()  void MainWindow::on_loader_finished()
1487  {  {
1488      printf("Loader finished!\n");      printf("Loader finished!\n");
1489      printf("on_loader_finished self=%x\n", Glib::Thread::self());      printf("on_loader_finished self=%p\n",
1490      load_gig(loader->gig, loader->filename);             static_cast<void*>(Glib::Threads::Thread::self()));
1491      load_dialog->hide();      load_gig(loader->gig, loader->filename.c_str());
1492        progress_dialog->hide();
1493    }
1494    
1495    void MainWindow::on_loader_error()
1496    {
1497        Glib::ustring txt = _("Could not load file: ") + loader->error_message;
1498        Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1499        msg.run();
1500        progress_dialog->hide();
1501  }  }
1502    
1503  void MainWindow::on_action_file_save()  void MainWindow::on_action_file_save()
# Line 694  bool MainWindow::file_save() Line 1536  bool MainWindow::file_save()
1536    
1537      std::cout << "Saving file\n" << std::flush;      std::cout << "Saving file\n" << std::flush;
1538      file_structure_to_be_changed_signal.emit(this->file);      file_structure_to_be_changed_signal.emit(this->file);
1539      try {  
1540          file->Save();      progress_dialog = new ProgressDialog( //FIXME: memory leak!
1541          if (file_is_changed) {          _("Saving") +  Glib::ustring(" '") +
1542              set_title(get_title().substr(1));          Glib::filename_display_basename(this->filename) + "' ...",
1543              file_is_changed = false;          *this
1544          }      );
1545      } catch (RIFF::Exception e) {      progress_dialog->show_all();
1546          file_structure_changed_signal.emit(this->file);      saver = new Saver(this->file); //FIXME: memory leak!
1547          Glib::ustring txt = _("Could not save file: ") + e.Message;      saver->signal_progress().connect(
1548          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          sigc::mem_fun(*this, &MainWindow::on_saver_progress));
1549          msg.run();      saver->signal_finished().connect(
1550          return false;          sigc::mem_fun(*this, &MainWindow::on_saver_finished));
1551      }      saver->signal_error().connect(
1552      std::cout << "Saving file done\n" << std::flush;          sigc::mem_fun(*this, &MainWindow::on_saver_error));
1553        saver->launch();
1554    
1555        return true;
1556    }
1557    
1558    void MainWindow::on_saver_progress()
1559    {
1560        progress_dialog->set_fraction(saver->get_progress());
1561    }
1562    
1563    void MainWindow::on_saver_error()
1564    {
1565        file_structure_changed_signal.emit(this->file);
1566        Glib::ustring txt = _("Could not save file: ") + saver->error_message;
1567        Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1568        msg.run();
1569    }
1570    
1571    void MainWindow::on_saver_finished()
1572    {
1573        this->file = saver->gig;
1574        this->filename = saver->filename;
1575        current_gig_dir = Glib::path_get_dirname(filename);
1576        set_title(Glib::filename_display_basename(filename));
1577        file_has_name = true;
1578        file_is_changed = false;
1579        std::cout << "Saving file done. Importing queued samples now ...\n" << std::flush;
1580      __import_queued_samples();      __import_queued_samples();
1581        std::cout << "Importing queued samples done.\n" << std::flush;
1582    
1583      file_structure_changed_signal.emit(this->file);      file_structure_changed_signal.emit(this->file);
1584      return true;  
1585        __refreshEntireGUI();
1586        progress_dialog->hide();
1587  }  }
1588    
1589  void MainWindow::on_action_file_save_as()  void MainWindow::on_action_file_save_as()
# Line 727  bool MainWindow::file_save_as() Line 1600  bool MainWindow::file_save_as()
1600      dialog.set_default_response(Gtk::RESPONSE_OK);      dialog.set_default_response(Gtk::RESPONSE_OK);
1601      dialog.set_do_overwrite_confirmation();      dialog.set_do_overwrite_confirmation();
1602    
1603    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1604      Gtk::FileFilter filter;      Gtk::FileFilter filter;
1605      filter.add_pattern("*.gig");      filter.add_pattern("*.gig");
1606    #else
1607        Glib::RefPtr<Gtk::FileFilter> filter = Gtk::FileFilter::create();
1608        filter->add_pattern("*.gig");
1609    #endif
1610      dialog.set_filter(filter);      dialog.set_filter(filter);
1611    
1612      // set initial dir and filename of the Save As dialog      // set initial dir and filename of the Save As dialog
# Line 749  bool MainWindow::file_save_as() Line 1627  bool MainWindow::file_save_as()
1627      // show warning in the dialog      // show warning in the dialog
1628      Gtk::HBox descriptionArea;      Gtk::HBox descriptionArea;
1629      descriptionArea.set_spacing(15);      descriptionArea.set_spacing(15);
1630      Gtk::Image warningIcon(Gtk::Stock::DIALOG_WARNING, Gtk::IconSize(Gtk::ICON_SIZE_DIALOG));      Gtk::Image warningIcon;
1631        warningIcon.set_from_icon_name("dialog-warning",
1632                                       Gtk::IconSize(Gtk::ICON_SIZE_DIALOG));
1633      descriptionArea.pack_start(warningIcon, Gtk::PACK_SHRINK);      descriptionArea.pack_start(warningIcon, Gtk::PACK_SHRINK);
1634    #if GTKMM_MAJOR_VERSION < 3
1635      view::WrapLabel description;      view::WrapLabel description;
1636    #else
1637        Gtk::Label description;
1638        description.set_line_wrap();
1639    #endif
1640      description.set_markup(      description.set_markup(
1641          _("\n<b>CAUTION:</b> You <b>MUST</b> use the "          _("\n<b>CAUTION:</b> You <b>MUST</b> use the "
1642            "<span style=\"italic\">\"Save\"</span> dialog instead of "            "<span style=\"italic\">\"Save\"</span> dialog instead of "
# Line 765  bool MainWindow::file_save_as() Line 1650  bool MainWindow::file_save_as()
1650      descriptionArea.show_all();      descriptionArea.show_all();
1651    
1652      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
1653          file_structure_to_be_changed_signal.emit(this->file);          std::string filename = dialog.get_filename();
1654          try {          if (!Glib::str_has_suffix(filename, ".gig")) {
1655              std::string filename = dialog.get_filename();              filename += ".gig";
             if (!Glib::str_has_suffix(filename, ".gig")) {  
                 filename += ".gig";  
             }  
             printf("filename=%s\n", filename.c_str());  
             file->Save(filename);  
             this->filename = filename;  
             current_gig_dir = Glib::path_get_dirname(filename);  
             set_title(Glib::filename_display_basename(filename));  
             file_has_name = true;  
             file_is_changed = false;  
         } catch (RIFF::Exception e) {  
             file_structure_changed_signal.emit(this->file);  
             Glib::ustring txt = _("Could not save file: ") + e.Message;  
             Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);  
             msg.run();  
             return false;  
1656          }          }
1657          __import_queued_samples();          printf("filename=%s\n", filename.c_str());
1658          file_structure_changed_signal.emit(this->file);  
1659            progress_dialog = new ProgressDialog( //FIXME: memory leak!
1660                _("Saving") +  Glib::ustring(" '") +
1661                Glib::filename_display_basename(filename) + "' ...",
1662                *this
1663            );
1664            progress_dialog->show_all();
1665    
1666            saver = new Saver(file, filename); //FIXME: memory leak!
1667            saver->signal_progress().connect(
1668                sigc::mem_fun(*this, &MainWindow::on_saver_progress));
1669            saver->signal_finished().connect(
1670                sigc::mem_fun(*this, &MainWindow::on_saver_finished));
1671            saver->signal_error().connect(
1672                sigc::mem_fun(*this, &MainWindow::on_saver_error));
1673            saver->launch();
1674    
1675          return true;          return true;
1676      }      }
1677      return false;      return false;
# Line 796  bool MainWindow::file_save_as() Line 1681  bool MainWindow::file_save_as()
1681  void MainWindow::__import_queued_samples() {  void MainWindow::__import_queued_samples() {
1682      std::cout << "Starting sample import\n" << std::flush;      std::cout << "Starting sample import\n" << std::flush;
1683      Glib::ustring error_files;      Glib::ustring error_files;
1684      printf("Samples to import: %d\n", m_SampleImportQueue.size());      printf("Samples to import: %d\n", int(m_SampleImportQueue.size()));
1685      for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();      for (std::map<gig::Sample*, SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1686           iter != m_SampleImportQueue.end(); ) {           iter != m_SampleImportQueue.end(); ) {
1687          printf("Importing sample %s\n",(*iter).sample_path.c_str());          printf("Importing sample %s\n",iter->second.sample_path.c_str());
1688          SF_INFO info;          SF_INFO info;
1689          info.format = 0;          info.format = 0;
1690          SNDFILE* hFile = sf_open((*iter).sample_path.c_str(), SFM_READ, &info);          SNDFILE* hFile = sf_open(iter->second.sample_path.c_str(), SFM_READ, &info);
1691            sf_command(hFile, SFC_SET_SCALE_FLOAT_INT_READ, 0, SF_TRUE);
1692          try {          try {
1693              if (!hFile) throw std::string(_("could not open file"));              if (!hFile) throw std::string(_("could not open file"));
1694              // determine sample's bit depth              // determine sample's bit depth
# Line 824  void MainWindow::__import_queued_samples Line 1710  void MainWindow::__import_queued_samples
1710                      throw std::string(_("format not supported")); // unsupported subformat (yet?)                      throw std::string(_("format not supported")); // unsupported subformat (yet?)
1711              }              }
1712    
1713                // reset write position for sample
1714                iter->first->SetPos(0);
1715    
1716              const int bufsize = 10000;              const int bufsize = 10000;
1717              switch (bitdepth) {              switch (bitdepth) {
1718                  case 16: {                  case 16: {
# Line 833  void MainWindow::__import_queued_samples Line 1722  void MainWindow::__import_queued_samples
1722                          // libsndfile does the conversion for us (if needed)                          // libsndfile does the conversion for us (if needed)
1723                          int n = sf_readf_short(hFile, buffer, bufsize);                          int n = sf_readf_short(hFile, buffer, bufsize);
1724                          // write from buffer directly (physically) into .gig file                          // write from buffer directly (physically) into .gig file
1725                          iter->gig_sample->Write(buffer, n);                          iter->first->Write(buffer, n);
1726                          cnt -= n;                          cnt -= n;
1727                      }                      }
1728                      delete[] buffer;                      delete[] buffer;
# Line 853  void MainWindow::__import_queued_samples Line 1742  void MainWindow::__import_queued_samples
1742                              dstbuf[j++] = srcbuf[i] >> 24;                              dstbuf[j++] = srcbuf[i] >> 24;
1743                          }                          }
1744                          // write from buffer directly (physically) into .gig file                          // write from buffer directly (physically) into .gig file
1745                          iter->gig_sample->Write(dstbuf, n);                          iter->first->Write(dstbuf, n);
1746                          cnt -= n;                          cnt -= n;
1747                      }                      }
1748                      delete[] srcbuf;                      delete[] srcbuf;
# Line 864  void MainWindow::__import_queued_samples Line 1753  void MainWindow::__import_queued_samples
1753              // cleanup              // cleanup
1754              sf_close(hFile);              sf_close(hFile);
1755              // let the sampler re-cache the sample if needed              // let the sampler re-cache the sample if needed
1756              sample_changed_signal.emit(iter->gig_sample);              sample_changed_signal.emit(iter->first);
1757              // on success we remove the sample from the import queue,              // on success we remove the sample from the import queue,
1758              // otherwise keep it, maybe it works the next time ?              // otherwise keep it, maybe it works the next time ?
1759              std::list<SampleImportItem>::iterator cur = iter;              std::map<gig::Sample*, SampleImportItem>::iterator cur = iter;
1760              ++iter;              ++iter;
1761              m_SampleImportQueue.erase(cur);              m_SampleImportQueue.erase(cur);
1762          } catch (std::string what) {          } catch (std::string what) {
1763              // remember the files that made trouble (and their cause)              // remember the files that made trouble (and their cause)
1764              if (error_files.size()) error_files += "\n";              if (!error_files.empty()) error_files += "\n";
1765              error_files += (*iter).sample_path += " (" + what + ")";              error_files += iter->second.sample_path += " (" + what + ")";
1766              ++iter;              ++iter;
1767          }          }
1768      }      }
1769      // show error message box when some sample(s) could not be imported      // show error message box when some sample(s) could not be imported
1770      if (error_files.size()) {      if (!error_files.empty()) {
1771          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;
1772          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1773          msg.run();          msg.run();
# Line 891  void MainWindow::on_action_file_properti Line 1780  void MainWindow::on_action_file_properti
1780      propDialog.deiconify();      propDialog.deiconify();
1781  }  }
1782    
1783    void MainWindow::on_action_warn_user_on_extensions() {
1784        Settings::singleton()->warnUserOnExtensions =
1785            !Settings::singleton()->warnUserOnExtensions;
1786    }
1787    
1788    void MainWindow::on_action_sync_sampler_instrument_selection() {
1789        Settings::singleton()->syncSamplerInstrumentSelection =
1790            !Settings::singleton()->syncSamplerInstrumentSelection;
1791    }
1792    
1793    void MainWindow::on_action_move_root_note_with_region_moved() {
1794        Settings::singleton()->moveRootNoteWithRegionMoved =
1795            !Settings::singleton()->moveRootNoteWithRegionMoved;
1796    }
1797    
1798  void MainWindow::on_action_help_about()  void MainWindow::on_action_help_about()
1799  {  {
1800      Gtk::AboutDialog dialog;      Gtk::AboutDialog dialog;
# Line 900  void MainWindow::on_action_help_about() Line 1804  void MainWindow::on_action_help_about()
1804      dialog.set_name("Gigedit");      dialog.set_name("Gigedit");
1805  #endif  #endif
1806      dialog.set_version(VERSION);      dialog.set_version(VERSION);
1807      dialog.set_copyright("Copyright (C) 2006-2010 Andreas Persson");      dialog.set_copyright("Copyright (C) 2006-2017 Andreas Persson");
1808      dialog.set_comments(_(      const std::string sComment =
1809          "Released under the GNU General Public License.\n"          _("Built " __DATE__ "\nUsing ") +
1810          "\n"          ::gig::libraryName() + " " + ::gig::libraryVersion() + "\n\n" +
1811          "Please notice that this is still a very young instrument editor. "          _(
1812          "So better backup your Gigasampler files before editing them with "              "Gigedit is released under the GNU General Public License.\n"
1813          "this application.\n"              "\n"
1814          "\n"              "This program is distributed WITHOUT ANY WARRANTY; So better "
1815          "Please report bugs to: http://bugs.linuxsampler.org")              "backup your Gigasampler/GigaStudio files before editing them with "
1816      );              "this application.\n"
1817                "\n"
1818                "Please report bugs to: http://bugs.linuxsampler.org"
1819            );
1820        dialog.set_comments(sComment.c_str());
1821      dialog.set_website("http://www.linuxsampler.org");      dialog.set_website("http://www.linuxsampler.org");
1822      dialog.set_website_label("http://www.linuxsampler.org");      dialog.set_website_label("http://www.linuxsampler.org");
1823        dialog.set_position(Gtk::WIN_POS_CENTER);
1824      dialog.run();      dialog.run();
1825  }  }
1826    
1827  PropDialog::PropDialog()  PropDialog::PropDialog()
1828      : eName(_("Name")),      : eFileFormat(_("File Format")),
1829          eName(_("Name")),
1830        eCreationDate(_("Creation date")),        eCreationDate(_("Creation date")),
1831        eComments(_("Comments")),        eComments(_("Comments")),
1832        eProduct(_("Product")),        eProduct(_("Product")),
# Line 934  PropDialog::PropDialog() Line 1844  PropDialog::PropDialog()
1844        eSubject(_("Subject")),        eSubject(_("Subject")),
1845        quitButton(Gtk::Stock::CLOSE),        quitButton(Gtk::Stock::CLOSE),
1846        table(2, 1),        table(2, 1),
1847        update_model(0)        m_file(NULL)
1848  {  {
1849        if (!Settings::singleton()->autoRestoreWindowDimension) {
1850            set_default_size(470, 390);
1851            set_position(Gtk::WIN_POS_MOUSE);
1852        }
1853    
1854      set_title(_("File Properties"));      set_title(_("File Properties"));
1855      eName.set_width_chars(50);      eName.set_width_chars(50);
1856    
# Line 956  PropDialog::PropDialog() Line 1871  PropDialog::PropDialog()
1871      connect(eCommissioned, &DLS::Info::Commissioned);      connect(eCommissioned, &DLS::Info::Commissioned);
1872      connect(eSubject, &DLS::Info::Subject);      connect(eSubject, &DLS::Info::Subject);
1873    
1874        table.add(eFileFormat);
1875      table.add(eName);      table.add(eName);
1876      table.add(eCreationDate);      table.add(eCreationDate);
1877      table.add(eComments);      table.add(eComments);
# Line 986  PropDialog::PropDialog() Line 1902  PropDialog::PropDialog()
1902      quitButton.grab_focus();      quitButton.grab_focus();
1903      quitButton.signal_clicked().connect(      quitButton.signal_clicked().connect(
1904          sigc::mem_fun(*this, &PropDialog::hide));          sigc::mem_fun(*this, &PropDialog::hide));
1905        eFileFormat.signal_value_changed().connect(
1906            sigc::mem_fun(*this, &PropDialog::onFileFormatChanged));
1907    
1908      quitButton.show();      quitButton.show();
1909      vbox.show();      vbox.show();
1910      show_all_children();      show_all_children();
1911  }  }
1912    
1913  void PropDialog::set_info(DLS::Info* info)  void PropDialog::set_file(gig::File* file)
1914  {  {
1915      this->info = info;      m_file = file;
1916      update_model++;  
1917      eName.set_value(info->Name);      // update file format version combo box
1918      eCreationDate.set_value(info->CreationDate);      const std::string sGiga = "Gigasampler/GigaStudio v";
1919      eComments.set_value(info->Comments);      const int major = file->pVersion->major;
1920      eProduct.set_value(info->Product);      std::vector<std::string> txts;
1921      eCopyright.set_value(info->Copyright);      std::vector<int> values;
1922      eArtists.set_value(info->Artists);      txts.push_back(sGiga + "2"); values.push_back(2);
1923      eGenre.set_value(info->Genre);      txts.push_back(sGiga + "3/v4"); values.push_back(3);
1924      eKeywords.set_value(info->Keywords);      if (major != 2 && major != 3) {
1925      eEngineer.set_value(info->Engineer);          txts.push_back(sGiga + ToString(major)); values.push_back(major);
1926      eTechnician.set_value(info->Technician);      }
1927      eSoftware.set_value(info->Software);      std::vector<const char*> texts;
1928      eMedium.set_value(info->Medium);      for (int i = 0; i < txts.size(); ++i) texts.push_back(txts[i].c_str());
1929      eSource.set_value(info->Source);      texts.push_back(NULL); values.push_back(0);
1930      eSourceForm.set_value(info->SourceForm);      eFileFormat.set_choices(&texts[0], &values[0]);
1931      eCommissioned.set_value(info->Commissioned);      eFileFormat.set_value(major);
1932      eSubject.set_value(info->Subject);  }
1933      update_model--;  
1934    void PropDialog::onFileFormatChanged() {
1935        const int major = eFileFormat.get_value();
1936        if (m_file) m_file->pVersion->major = major;
1937  }  }
1938    
1939  sigc::signal<void>& PropDialog::signal_info_changed()  void PropDialog::set_info(DLS::Info* info)
1940  {  {
1941      return info_changed;      update(info);
1942  }  }
1943    
1944  void InstrumentProps::set_IsDrum(bool value)  
1945    void InstrumentProps::set_Name(const gig::String& name)
1946  {  {
1947      instrument->IsDrum = value;      m->pInfo->Name = name;
1948  }  }
1949    
1950  void InstrumentProps::set_MIDIBank(uint16_t value)  void InstrumentProps::update_name()
1951  {  {
1952      instrument->MIDIBank = value;      update_model++;
1953        eName.set_value(m->pInfo->Name);
1954        update_model--;
1955  }  }
1956    
1957  void InstrumentProps::set_MIDIProgram(uint32_t value)  void InstrumentProps::set_IsDrum(bool value)
1958  {  {
1959      instrument->MIDIProgram = value;      m->IsDrum = value;
1960  }  }
1961    
1962  void InstrumentProps::set_DimensionKeyRange_low(uint8_t value)  void InstrumentProps::set_MIDIBank(uint16_t value)
1963  {  {
1964      instrument->DimensionKeyRange.low = value;      m->MIDIBank = value;
     if (value > instrument->DimensionKeyRange.high) {  
         eDimensionKeyRangeHigh.set_value(value);  
     }  
1965  }  }
1966    
1967  void InstrumentProps::set_DimensionKeyRange_high(uint8_t value)  void InstrumentProps::set_MIDIProgram(uint32_t value)
1968  {  {
1969      instrument->DimensionKeyRange.high = value;      m->MIDIProgram = value;
     if (value < instrument->DimensionKeyRange.low) {  
         eDimensionKeyRangeLow.set_value(value);  
     }  
1970  }  }
1971    
1972  InstrumentProps::InstrumentProps()  InstrumentProps::InstrumentProps() :
1973      : update_model(0),      quitButton(Gtk::Stock::CLOSE),
1974        quitButton(Gtk::Stock::CLOSE),      table(2,1),
1975        table(2,1),      eName(_("Name")),
1976        eName(_("Name")),      eIsDrum(_("Is drum")),
1977        eIsDrum(_("Is drum")),      eMIDIBank(_("MIDI bank"), 0, 16383),
1978        eMIDIBank(_("MIDI bank"), 0, 16383),      eMIDIProgram(_("MIDI program")),
1979        eMIDIProgram(_("MIDI program")),      eAttenuation(_("Attenuation"), 0, 96, 0, 1),
1980        eAttenuation(_("Attenuation"), 0, 96, 0, 1),      eGainPlus6(_("Gain +6dB"), eAttenuation, -6),
1981        eGainPlus6(_("Gain +6dB"), eAttenuation, -6),      eEffectSend(_("Effect send"), 0, 65535),
1982        eEffectSend(_("Effect send"), 0, 65535),      eFineTune(_("Fine tune"), -8400, 8400),
1983        eFineTune(_("Fine tune"), -8400, 8400),      ePitchbendRange(_("Pitchbend range"), 0, 12),
1984        ePitchbendRange(_("Pitchbend range"), 0, 12),      ePianoReleaseMode(_("Piano release mode")),
1985        ePianoReleaseMode(_("Piano release mode")),      eDimensionKeyRangeLow(_("Keyswitching range low")),
1986        eDimensionKeyRangeLow(_("Keyswitching range low")),      eDimensionKeyRangeHigh(_("Keyswitching range high"))
1987        eDimensionKeyRangeHigh(_("Keyswitching range high"))  {
1988  {      if (!Settings::singleton()->autoRestoreWindowDimension) {
1989            //set_default_size(470, 390);
1990            set_position(Gtk::WIN_POS_MOUSE);
1991        }
1992    
1993      set_title(_("Instrument Properties"));      set_title(_("Instrument Properties"));
1994    
1995      eDimensionKeyRangeLow.set_tip(      eDimensionKeyRangeLow.set_tip(
# Line 1079  InstrumentProps::InstrumentProps() Line 2001  InstrumentProps::InstrumentProps()
2001            "\"keyswitching\" dimension")            "\"keyswitching\" dimension")
2002      );      );
2003    
2004        connect(eName, &InstrumentProps::set_Name);
2005      connect(eIsDrum, &InstrumentProps::set_IsDrum);      connect(eIsDrum, &InstrumentProps::set_IsDrum);
2006      connect(eMIDIBank, &InstrumentProps::set_MIDIBank);      connect(eMIDIBank, &InstrumentProps::set_MIDIBank);
2007      connect(eMIDIProgram, &InstrumentProps::set_MIDIProgram);      connect(eMIDIProgram, &InstrumentProps::set_MIDIProgram);
# Line 1088  InstrumentProps::InstrumentProps() Line 2011  InstrumentProps::InstrumentProps()
2011      connect(eFineTune, &gig::Instrument::FineTune);      connect(eFineTune, &gig::Instrument::FineTune);
2012      connect(ePitchbendRange, &gig::Instrument::PitchbendRange);      connect(ePitchbendRange, &gig::Instrument::PitchbendRange);
2013      connect(ePianoReleaseMode, &gig::Instrument::PianoReleaseMode);      connect(ePianoReleaseMode, &gig::Instrument::PianoReleaseMode);
2014      connect(eDimensionKeyRangeLow,      connect(eDimensionKeyRangeLow, eDimensionKeyRangeHigh,
2015              &InstrumentProps::set_DimensionKeyRange_low);              &gig::Instrument::DimensionKeyRange);
2016      connect(eDimensionKeyRangeHigh,  
2017              &InstrumentProps::set_DimensionKeyRange_high);      eName.signal_value_changed().connect(sig_name_changed.make_slot());
2018    
2019      table.set_col_spacings(5);      table.set_col_spacings(5);
2020    
# Line 1130  InstrumentProps::InstrumentProps() Line 2053  InstrumentProps::InstrumentProps()
2053    
2054  void InstrumentProps::set_instrument(gig::Instrument* instrument)  void InstrumentProps::set_instrument(gig::Instrument* instrument)
2055  {  {
2056      this->instrument = instrument;      update(instrument);
2057    
2058      update_model++;      update_model++;
2059      eName.set_value(instrument->pInfo->Name);      eName.set_value(instrument->pInfo->Name);
2060      eIsDrum.set_value(instrument->IsDrum);      eIsDrum.set_value(instrument->IsDrum);
2061      eMIDIBank.set_value(instrument->MIDIBank);      eMIDIBank.set_value(instrument->MIDIBank);
2062      eMIDIProgram.set_value(instrument->MIDIProgram);      eMIDIProgram.set_value(instrument->MIDIProgram);
     eAttenuation.set_value(instrument->Attenuation);  
     eGainPlus6.set_value(instrument->Attenuation);  
     eEffectSend.set_value(instrument->EffectSend);  
     eFineTune.set_value(instrument->FineTune);  
     ePitchbendRange.set_value(instrument->PitchbendRange);  
     ePianoReleaseMode.set_value(instrument->PianoReleaseMode);  
     eDimensionKeyRangeLow.set_value(instrument->DimensionKeyRange.low);  
     eDimensionKeyRangeHigh.set_value(instrument->DimensionKeyRange.high);  
2063      update_model--;      update_model--;
2064  }  }
2065    
 sigc::signal<void>& InstrumentProps::signal_instrument_changed()  
 {  
     return instrument_changed;  
 }  
2066    
2067  void MainWindow::file_changed()  void MainWindow::file_changed()
2068  {  {
# Line 1161  void MainWindow::file_changed() Line 2072  void MainWindow::file_changed()
2072      }      }
2073  }  }
2074    
2075    void MainWindow::updateSampleRefCountMap(gig::File* gig) {
2076        sample_ref_count.clear();
2077        
2078        if (!gig) return;
2079    
2080        for (gig::Instrument* instrument = gig->GetFirstInstrument(); instrument;
2081             instrument = gig->GetNextInstrument())
2082        {
2083            for (gig::Region* rgn = instrument->GetFirstRegion(); rgn;
2084                 rgn = instrument->GetNextRegion())
2085            {
2086                for (int i = 0; i < 256; ++i) {
2087                    if (!rgn->pDimensionRegions[i]) continue;
2088                    if (rgn->pDimensionRegions[i]->pSample) {
2089                        sample_ref_count[rgn->pDimensionRegions[i]->pSample]++;
2090                    }
2091                }
2092            }
2093        }
2094    }
2095    
2096  void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)  void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)
2097  {  {
2098      file = 0;      file = 0;
2099      set_file_is_shared(isSharedInstrument);      set_file_is_shared(isSharedInstrument);
2100    
2101      this->filename = filename ? filename : _("Unsaved Gig File");      this->filename =
2102            (filename && strlen(filename) > 0) ?
2103                filename : (!gig->GetFileName().empty()) ?
2104                    gig->GetFileName() : _("Unsaved Gig File");
2105      set_title(Glib::filename_display_basename(this->filename));      set_title(Glib::filename_display_basename(this->filename));
2106      file_has_name = filename;      file_has_name = filename;
2107      file_is_changed = false;      file_is_changed = false;
2108    
2109        propDialog.set_file(gig);
2110      propDialog.set_info(gig->pInfo);      propDialog.set_info(gig->pInfo);
2111    
2112      Gtk::MenuItem* instrument_menu =      instrument_name_connection.block();
2113          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));      int index = 0;
   
     int instrument_index = 0;  
     Gtk::RadioMenuItem::Group instrument_group;  
2114      for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;      for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;
2115           instrument = gig->GetNextInstrument()) {           instrument = gig->GetNextInstrument(), ++index) {
2116            Glib::ustring name(gig_to_utf8(instrument->pInfo->Name));
2117            const int iScriptSlots = instrument->ScriptSlotCount();
2118    
2119          Gtk::TreeModel::iterator iter = m_refTreeModel->append();          Gtk::TreeModel::iterator iter = m_refTreeModel->append();
2120          Gtk::TreeModel::Row row = *iter;          Gtk::TreeModel::Row row = *iter;
2121          row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();          row[m_Columns.m_col_nr] = index;
2122            row[m_Columns.m_col_name] = name;
2123          row[m_Columns.m_col_instr] = instrument;          row[m_Columns.m_col_instr] = instrument;
2124          // create a menu item for this instrument          row[m_Columns.m_col_scripts] = iScriptSlots ? ToString(iScriptSlots) : "";
2125          Gtk::RadioMenuItem* item =  
2126              new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());          add_instrument_to_menu(name);
         instrument_menu->get_submenu()->append(*item);  
         item->signal_activate().connect(  
             sigc::bind(  
                 sigc::mem_fun(*this, &MainWindow::on_instrument_selection_change),  
                 instrument_index  
             )  
         );  
         instrument_index++;  
2127      }      }
2128      instrument_menu->show();      instrument_name_connection.unblock();
2129      instrument_menu->get_submenu()->show_all_children();      uiManager->get_widget("/MenuBar/MenuInstrument/AllInstruments")->show();
2130    
2131        updateSampleRefCountMap(gig);
2132    
2133      for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {      for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
2134          if (group->Name != "") {          if (group->Name != "") {
2135              Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();              Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
2136              Gtk::TreeModel::Row rowGroup = *iterGroup;              Gtk::TreeModel::Row rowGroup = *iterGroup;
2137              rowGroup[m_SamplesModel.m_col_name]   = group->Name.c_str();              rowGroup[m_SamplesModel.m_col_name]   = gig_to_utf8(group->Name);
2138              rowGroup[m_SamplesModel.m_col_group]  = group;              rowGroup[m_SamplesModel.m_col_group]  = group;
2139              rowGroup[m_SamplesModel.m_col_sample] = NULL;              rowGroup[m_SamplesModel.m_col_sample] = NULL;
2140              for (gig::Sample* sample = group->GetFirstSample();              for (gig::Sample* sample = group->GetFirstSample();
# Line 1211  void MainWindow::load_gig(gig::File* gig Line 2142  void MainWindow::load_gig(gig::File* gig
2142                  Gtk::TreeModel::iterator iterSample =                  Gtk::TreeModel::iterator iterSample =
2143                      m_refSamplesTreeModel->append(rowGroup.children());                      m_refSamplesTreeModel->append(rowGroup.children());
2144                  Gtk::TreeModel::Row rowSample = *iterSample;                  Gtk::TreeModel::Row rowSample = *iterSample;
2145                  rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();                  rowSample[m_SamplesModel.m_col_name] =
2146                        gig_to_utf8(sample->pInfo->Name);
2147                  rowSample[m_SamplesModel.m_col_sample] = sample;                  rowSample[m_SamplesModel.m_col_sample] = sample;
2148                  rowSample[m_SamplesModel.m_col_group]  = NULL;                  rowSample[m_SamplesModel.m_col_group]  = NULL;
2149                    int refcount = sample_ref_count.count(sample) ? sample_ref_count[sample] : 0;
2150                    rowSample[m_SamplesModel.m_col_refcount] = ToString(refcount) + " " + _("Refs.");
2151                    rowSample[m_SamplesModel.m_color] = refcount ? "black" : "red";
2152              }              }
2153          }          }
2154      }      }
2155        
2156        for (int i = 0; gig->GetScriptGroup(i); ++i) {
2157            gig::ScriptGroup* group = gig->GetScriptGroup(i);
2158    
2159            Gtk::TreeModel::iterator iterGroup = m_refScriptsTreeModel->append();
2160            Gtk::TreeModel::Row rowGroup = *iterGroup;
2161            rowGroup[m_ScriptsModel.m_col_name]   = gig_to_utf8(group->Name);
2162            rowGroup[m_ScriptsModel.m_col_group]  = group;
2163            rowGroup[m_ScriptsModel.m_col_script] = NULL;
2164            for (int s = 0; group->GetScript(s); ++s) {
2165                gig::Script* script = group->GetScript(s);
2166    
2167                Gtk::TreeModel::iterator iterScript =
2168                    m_refScriptsTreeModel->append(rowGroup.children());
2169                Gtk::TreeModel::Row rowScript = *iterScript;
2170                rowScript[m_ScriptsModel.m_col_name] = gig_to_utf8(script->Name);
2171                rowScript[m_ScriptsModel.m_col_script] = script;
2172                rowScript[m_ScriptsModel.m_col_group]  = NULL;
2173            }
2174        }
2175        // unfold all sample groups & script groups by default
2176        m_TreeViewSamples.expand_all();
2177        m_TreeViewScripts.expand_all();
2178    
2179      file = gig;      file = gig;
2180    
2181      // select the first instrument      // select the first instrument
2182      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      m_TreeView.get_selection()->select(Gtk::TreePath("0"));
2183      tree_sel_ref->select(Gtk::TreePath("0"));  
2184        instr_props_set_instrument();
2185        gig::Instrument* instrument = get_instrument();
2186        if (instrument) {
2187            midiRules.set_instrument(instrument);
2188        }
2189  }  }
2190    
2191  void MainWindow::show_instr_props()  bool MainWindow::instr_props_set_instrument()
2192  {  {
2193      gig::Instrument* instrument = get_instrument();      instrumentProps.signal_name_changed().clear();
2194      if (instrument)  
2195      {      std::vector<Gtk::TreeModel::Path> rows = m_TreeView.get_selection()->get_selected_rows();
2196        if (rows.empty()) {
2197            instrumentProps.hide();
2198            return false;
2199        }
2200        Gtk::TreeModel::const_iterator it = m_refTreeModel->get_iter(rows[0]);
2201        if (it) {
2202            Gtk::TreeModel::Row row = *it;
2203            gig::Instrument* instrument = row[m_Columns.m_col_instr];
2204    
2205          instrumentProps.set_instrument(instrument);          instrumentProps.set_instrument(instrument);
2206    
2207            // make sure instrument tree is updated when user changes the
2208            // instrument name in instrument properties window
2209            instrumentProps.signal_name_changed().connect(
2210                sigc::bind(
2211                    sigc::mem_fun(*this,
2212                                  &MainWindow::instr_name_changed_by_instr_props),
2213                    it));
2214        } else {
2215            instrumentProps.hide();
2216        }
2217        return it;
2218    }
2219    
2220    void MainWindow::show_instr_props()
2221    {
2222        if (instr_props_set_instrument()) {
2223          instrumentProps.show();          instrumentProps.show();
2224          instrumentProps.deiconify();          instrumentProps.deiconify();
2225      }      }
2226  }  }
2227    
2228    void MainWindow::instr_name_changed_by_instr_props(Gtk::TreeModel::iterator& it)
2229    {
2230        Gtk::TreeModel::Row row = *it;
2231        Glib::ustring name = row[m_Columns.m_col_name];
2232    
2233        gig::Instrument* instrument = row[m_Columns.m_col_instr];
2234        Glib::ustring gigname(gig_to_utf8(instrument->pInfo->Name));
2235        if (gigname != name) {
2236            row[m_Columns.m_col_name] = gigname;
2237        }
2238    }
2239    
2240    void MainWindow::show_midi_rules()
2241    {
2242        if (gig::Instrument* instrument = get_instrument())
2243        {
2244            midiRules.set_instrument(instrument);
2245            midiRules.show();
2246            midiRules.deiconify();
2247        }
2248    }
2249    
2250    void MainWindow::show_script_slots() {
2251        if (!file) return;
2252        // get selected instrument
2253        std::vector<Gtk::TreeModel::Path> rows = m_TreeView.get_selection()->get_selected_rows();
2254        if (rows.empty()) return;
2255        Gtk::TreeModel::iterator it = m_refTreeModel->get_iter(rows[0]);
2256        if (!it) return;
2257        Gtk::TreeModel::Row row = *it;
2258        gig::Instrument* instrument = row[m_Columns.m_col_instr];
2259        if (!instrument) return;
2260    
2261        ScriptSlots* window = new ScriptSlots;
2262        window->setInstrument(instrument);
2263        window->signal_script_slots_changed().connect(
2264            sigc::mem_fun(*this, &MainWindow::onScriptSlotsModified)
2265        );
2266        //window->reparent(*this);
2267        window->show();
2268    }
2269    
2270    void MainWindow::onScriptSlotsModified(gig::Instrument* pInstrument) {
2271        if (!pInstrument) return;
2272        const int iScriptSlots = pInstrument->ScriptSlotCount();
2273    
2274        Glib::RefPtr<Gtk::TreeModel> model = m_TreeView.get_model();
2275        for (int i = 0; i < model->children().size(); ++i) {
2276            Gtk::TreeModel::Row row = model->children()[i];
2277            if (row[m_Columns.m_col_instr] != pInstrument) continue;
2278            row[m_Columns.m_col_scripts] = iScriptSlots ? ToString(iScriptSlots) : "";
2279            break;
2280        }
2281    }
2282    
2283    void MainWindow::on_action_refresh_all() {
2284        __refreshEntireGUI();
2285    }
2286    
2287  void MainWindow::on_action_view_status_bar() {  void MainWindow::on_action_view_status_bar() {
2288      Gtk::CheckMenuItem* item =      Gtk::CheckMenuItem* item =
2289          dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuView/Statusbar"));          dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuView/Statusbar"));
# Line 1247  void MainWindow::on_action_view_status_b Line 2295  void MainWindow::on_action_view_status_b
2295      else                    m_StatusBar.hide();      else                    m_StatusBar.hide();
2296  }  }
2297    
2298    void MainWindow::on_auto_restore_win_dim() {
2299        Gtk::CheckMenuItem* item =
2300            dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuView/AutoRestoreWinDim"));
2301        if (!item) {
2302            std::cerr << "/MenuBar/MenuView/AutoRestoreWinDim == NULL\n";
2303            return;
2304        }
2305        Settings::singleton()->autoRestoreWindowDimension = item->get_active();
2306    }
2307    
2308    void MainWindow::on_save_with_temporary_file() {
2309        Gtk::CheckMenuItem* item =
2310            dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuSettings/SaveWithTemporaryFile"));
2311        if (!item) {
2312            std::cerr << "/MenuBar/MenuSettings/SaveWithTemporaryFile == NULL\n";
2313            return;
2314        }
2315        Settings::singleton()->saveWithTemporaryFile = item->get_active();
2316    }
2317    
2318    bool MainWindow::is_copy_samples_unity_note_enabled() const {
2319        Gtk::CheckMenuItem* item =
2320            dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuEdit/CopySampleUnity"));
2321        if (!item) {
2322            std::cerr << "/MenuBar/MenuEdit/CopySampleUnity == NULL\n";
2323            return true;
2324        }
2325        return item->get_active();
2326    }
2327    
2328    bool MainWindow::is_copy_samples_fine_tune_enabled() const {
2329        Gtk::CheckMenuItem* item =
2330            dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuEdit/CopySampleTune"));
2331        if (!item) {
2332            std::cerr << "/MenuBar/MenuEdit/CopySampleTune == NULL\n";
2333            return true;
2334        }
2335        return item->get_active();
2336    }
2337    
2338    bool MainWindow::is_copy_samples_loop_enabled() const {
2339        Gtk::CheckMenuItem* item =
2340            dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuEdit/CopySampleLoop"));
2341        if (!item) {
2342            std::cerr << "/MenuBar/MenuEdit/CopySampleLoop == NULL\n";
2343            return true;
2344        }
2345        return item->get_active();
2346    }
2347    
2348  void MainWindow::on_button_release(GdkEventButton* button)  void MainWindow::on_button_release(GdkEventButton* button)
2349  {  {
2350      if (button->type == GDK_2BUTTON_PRESS) {      if (button->type == GDK_2BUTTON_PRESS) {
2351          show_instr_props();          show_instr_props();
2352      } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {      } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
2353            // gig v2 files have no midi rules
2354            const bool bEnabled = !(file->pVersion && file->pVersion->major == 2);
2355            static_cast<Gtk::MenuItem*>(
2356                uiManager->get_widget("/MenuBar/MenuInstrument/MidiRules"))->set_sensitive(
2357                    bEnabled
2358                );
2359            static_cast<Gtk::MenuItem*>(
2360                uiManager->get_widget("/PopupMenu/MidiRules"))->set_sensitive(
2361                    bEnabled
2362                );
2363          popup_menu->popup(button->button, button->time);          popup_menu->popup(button->button, button->time);
2364      }      }
2365  }  }
2366    
2367  void MainWindow::on_instrument_selection_change(int index) {  void MainWindow::on_instrument_selection_change(Gtk::RadioMenuItem* item) {
2368      m_RegionChooser.set_instrument(file->GetInstrument(index));      if (item->get_active()) {
2369            const std::vector<Gtk::Widget*> children =
2370                instrument_menu->get_children();
2371            std::vector<Gtk::Widget*>::const_iterator it =
2372                find(children.begin(), children.end(), item);
2373            if (it != children.end()) {
2374                int index = it - children.begin();
2375                m_TreeView.get_selection()->select(Gtk::TreePath(ToString(index)));
2376    
2377                m_RegionChooser.set_instrument(file->GetInstrument(index));
2378            }
2379        }
2380    }
2381    
2382    void MainWindow::select_instrument(gig::Instrument* instrument) {
2383        if (!instrument) return;
2384    
2385        Glib::RefPtr<Gtk::TreeModel> model = m_TreeView.get_model();
2386        for (int i = 0; i < model->children().size(); ++i) {
2387            Gtk::TreeModel::Row row = model->children()[i];
2388            if (row[m_Columns.m_col_instr] == instrument) {
2389                // select and show the respective instrument in the list view
2390                show_intruments_tab();
2391                m_TreeView.get_selection()->unselect_all();
2392                m_TreeView.get_selection()->select(model->children()[i]);
2393                std::vector<Gtk::TreeModel::Path> rows =
2394                    m_TreeView.get_selection()->get_selected_rows();
2395                if (!rows.empty())
2396                    m_TreeView.scroll_to_row(rows[0]);
2397                on_sel_change(); // the regular instrument selection change callback
2398            }
2399        }
2400    }
2401    
2402    /// Returns true if requested dimension region was successfully selected and scrolled to in the list view, false on error.
2403    bool MainWindow::select_dimension_region(gig::DimensionRegion* dimRgn) {
2404        gig::Region* pRegion = (gig::Region*) dimRgn->GetParent();
2405        gig::Instrument* pInstrument = (gig::Instrument*) pRegion->GetParent();
2406    
2407        Glib::RefPtr<Gtk::TreeModel> model = m_TreeView.get_model();
2408        for (int i = 0; i < model->children().size(); ++i) {
2409            Gtk::TreeModel::Row row = model->children()[i];
2410            if (row[m_Columns.m_col_instr] == pInstrument) {
2411                // select and show the respective instrument in the list view
2412                show_intruments_tab();
2413                m_TreeView.get_selection()->unselect_all();
2414                m_TreeView.get_selection()->select(model->children()[i]);
2415                std::vector<Gtk::TreeModel::Path> rows =
2416                    m_TreeView.get_selection()->get_selected_rows();
2417                if (!rows.empty())
2418                    m_TreeView.scroll_to_row(rows[0]);
2419                on_sel_change(); // the regular instrument selection change callback
2420    
2421                // select respective region in the region selector
2422                m_RegionChooser.set_region(pRegion);
2423    
2424                // select and show the respective dimension region in the editor
2425                //update_dimregs();
2426                if (!m_DimRegionChooser.select_dimregion(dimRgn)) return false;
2427                //dimreg_edit.set_dim_region(dimRgn);
2428    
2429                return true;
2430            }
2431        }
2432    
2433        return false;
2434    }
2435    
2436    void MainWindow::select_sample(gig::Sample* sample) {
2437        Glib::RefPtr<Gtk::TreeModel> model = m_TreeViewSamples.get_model();
2438        for (int g = 0; g < model->children().size(); ++g) {
2439            Gtk::TreeModel::Row rowGroup = model->children()[g];
2440            for (int s = 0; s < rowGroup.children().size(); ++s) {
2441                Gtk::TreeModel::Row rowSample = rowGroup.children()[s];
2442                if (rowSample[m_SamplesModel.m_col_sample] == sample) {
2443                    show_samples_tab();
2444                    m_TreeViewSamples.get_selection()->unselect_all();
2445                    m_TreeViewSamples.get_selection()->select(rowGroup.children()[s]);
2446                    std::vector<Gtk::TreeModel::Path> rows =
2447                        m_TreeViewSamples.get_selection()->get_selected_rows();
2448                    if (rows.empty()) return;
2449                    m_TreeViewSamples.scroll_to_row(rows[0]);
2450                    return;
2451                }
2452            }
2453        }
2454  }  }
2455    
2456  void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {  void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {
2457      if (button->type == GDK_BUTTON_PRESS && button->button == 3) {      if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
2458            // by default if Ctrl keys is pressed down, then a mouse right-click
2459            // does not select the respective row, so we must assure this
2460            // programmatically ...
2461            /*{
2462                Gtk::TreeModel::Path path;
2463                Gtk::TreeViewColumn* pColumn = NULL;
2464                int cellX, cellY;
2465                bool bSuccess = m_TreeViewSamples.get_path_at_pos(
2466                    (int)button->x, (int)button->y,
2467                    path, pColumn, cellX, cellY
2468                );
2469                if (bSuccess) {
2470                    if (m_TreeViewSamples.get_selection()->count_selected_rows() <= 0) {
2471                        printf("not selected !!!\n");
2472                        m_TreeViewSamples.get_selection()->select(path);
2473                    }
2474                }
2475            }*/
2476    
2477          Gtk::Menu* sample_popup =          Gtk::Menu* sample_popup =
2478              dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/SamplePopupMenu"));              dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/SamplePopupMenu"));
2479          // update enabled/disabled state of sample popup items          // update enabled/disabled state of sample popup items
2480          Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();          Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
2481          Gtk::TreeModel::iterator it = sel->get_selected();          std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
2482          bool group_selected  = false;          const int n = rows.size();
2483          bool sample_selected = false;          int nGroups  = 0;
2484          if (it) {          int nSamples = 0;
2485            for (int r = 0; r < n; ++r) {
2486                Gtk::TreeModel::iterator it = m_refSamplesTreeModel->get_iter(rows[r]);
2487                if (!it) continue;
2488              Gtk::TreeModel::Row row = *it;              Gtk::TreeModel::Row row = *it;
2489              group_selected  = row[m_SamplesModel.m_col_group];              if (row[m_SamplesModel.m_col_group]) nGroups++;
2490              sample_selected = row[m_SamplesModel.m_col_sample];              if (row[m_SamplesModel.m_col_sample]) nSamples++;
2491          }          }
2492    
2493          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->
2494              set_sensitive(group_selected || sample_selected);              set_sensitive(n == 1);
2495          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->
2496              set_sensitive(group_selected || sample_selected);              set_sensitive(n);
2497          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->
2498              set_sensitive(file);              set_sensitive(file);
2499            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/ShowSampleRefs"))->
2500                set_sensitive(nSamples == 1);
2501          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->
2502              set_sensitive(group_selected || sample_selected);              set_sensitive(n);
2503          // show sample popup          // show sample popup
2504          sample_popup->popup(button->button, button->time);          sample_popup->popup(button->button, button->time);
2505    
2506            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuSample/SampleProperties"))->
2507                set_sensitive(n == 1);
2508            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuSample/AddSample"))->
2509                set_sensitive(n);
2510            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuSample/AddGroup"))->
2511                set_sensitive(file);
2512            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuSample/ShowSampleRefs"))->
2513                set_sensitive(nSamples == 1);
2514            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuSample/RemoveSample"))->
2515                set_sensitive(n);
2516      }      }
2517  }  }
2518    
2519  void MainWindow::on_action_add_instrument() {  void MainWindow::on_script_treeview_button_release(GdkEventButton* button) {
2520      static int __instrument_indexer = 0;      if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
2521      if (!file) return;          Gtk::Menu* script_popup =
2522      gig::Instrument* instrument = file->AddInstrument();              dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/ScriptPopupMenu"));
2523      __instrument_indexer++;          // update enabled/disabled state of sample popup items
2524      instrument->pInfo->Name =          Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewScripts.get_selection();
2525          _("Unnamed Instrument ") + ToString(__instrument_indexer);          Gtk::TreeModel::iterator it = sel->get_selected();
2526            bool group_selected  = false;
2527            bool script_selected = false;
2528            if (it) {
2529                Gtk::TreeModel::Row row = *it;
2530                group_selected  = row[m_ScriptsModel.m_col_group];
2531                script_selected = row[m_ScriptsModel.m_col_script];
2532            }
2533            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/ScriptPopupMenu/AddScript"))->
2534                set_sensitive(group_selected || script_selected);
2535            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/ScriptPopupMenu/AddScriptGroup"))->
2536                set_sensitive(file);
2537            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/ScriptPopupMenu/EditScript"))->
2538                set_sensitive(script_selected);    
2539            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/ScriptPopupMenu/RemoveScript"))->
2540                set_sensitive(group_selected || script_selected);
2541            // show sample popup
2542            script_popup->popup(button->button, button->time);
2543    
2544            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuScript/AddScript"))->
2545                set_sensitive(group_selected || script_selected);
2546            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuScript/AddScriptGroup"))->
2547                set_sensitive(file);
2548            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuScript/EditScript"))->
2549                set_sensitive(script_selected);    
2550            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuScript/RemoveScript"))->
2551                set_sensitive(group_selected || script_selected);
2552        }
2553    }
2554    
2555    Gtk::RadioMenuItem* MainWindow::add_instrument_to_menu(
2556        const Glib::ustring& name, int position) {
2557    
2558        Gtk::RadioMenuItem::Group instrument_group;
2559        const std::vector<Gtk::Widget*> children = instrument_menu->get_children();
2560        if (!children.empty()) {
2561            instrument_group =
2562                static_cast<Gtk::RadioMenuItem*>(children[0])->get_group();
2563        }
2564        Gtk::RadioMenuItem* item =
2565            new Gtk::RadioMenuItem(instrument_group, name);
2566        if (position < 0) {
2567            instrument_menu->append(*item);
2568        } else {
2569            instrument_menu->insert(*item, position);
2570        }
2571        item->show();
2572        item->signal_activate().connect(
2573            sigc::bind(
2574                sigc::mem_fun(*this, &MainWindow::on_instrument_selection_change),
2575                item));
2576        return item;
2577    }
2578    
2579    void MainWindow::remove_instrument_from_menu(int index) {
2580        const std::vector<Gtk::Widget*> children =
2581            instrument_menu->get_children();
2582        Gtk::Widget* child = children[index];
2583        instrument_menu->remove(*child);
2584        delete child;
2585    }
2586    
2587    void MainWindow::add_instrument(gig::Instrument* instrument) {
2588        const Glib::ustring name(gig_to_utf8(instrument->pInfo->Name));
2589    
2590      // update instrument tree view      // update instrument tree view
2591        instrument_name_connection.block();
2592      Gtk::TreeModel::iterator iterInstr = m_refTreeModel->append();      Gtk::TreeModel::iterator iterInstr = m_refTreeModel->append();
2593      Gtk::TreeModel::Row rowInstr = *iterInstr;      Gtk::TreeModel::Row rowInstr = *iterInstr;
2594      rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();      rowInstr[m_Columns.m_col_nr] = m_refTreeModel->children().size() - 1;
2595        rowInstr[m_Columns.m_col_name] = name;
2596      rowInstr[m_Columns.m_col_instr] = instrument;      rowInstr[m_Columns.m_col_instr] = instrument;
2597        rowInstr[m_Columns.m_col_scripts] = "";
2598        instrument_name_connection.unblock();
2599    
2600        add_instrument_to_menu(name);
2601    
2602        m_TreeView.get_selection()->select(iterInstr);
2603    
2604      file_changed();      file_changed();
2605  }  }
2606    
2607    void MainWindow::on_action_add_instrument() {
2608        static int __instrument_indexer = 0;
2609        if (!file) return;
2610        gig::Instrument* instrument = file->AddInstrument();
2611        __instrument_indexer++;
2612        instrument->pInfo->Name = gig_from_utf8(_("Unnamed Instrument ") +
2613                                                ToString(__instrument_indexer));
2614    
2615        add_instrument(instrument);
2616    }
2617    
2618    void MainWindow::on_action_duplicate_instrument() {
2619        if (!file) return;
2620    
2621        // retrieve the currently selected instrument
2622        // (being the original instrument to be duplicated)
2623        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
2624        std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
2625        for (int r = 0; r < rows.size(); ++r) {
2626            Gtk::TreeModel::iterator it = m_refTreeModel->get_iter(rows[r]);
2627            if (it) {
2628                Gtk::TreeModel::Row row = *it;
2629                gig::Instrument* instrOrig = row[m_Columns.m_col_instr];
2630                if (instrOrig) {
2631                    // duplicate the orginal instrument
2632                    gig::Instrument* instrNew = file->AddDuplicateInstrument(instrOrig);
2633                    instrNew->pInfo->Name =
2634                        instrOrig->pInfo->Name +
2635                        gig_from_utf8(Glib::ustring(" (") + _("Copy") + ")");
2636    
2637                    add_instrument(instrNew);
2638                }
2639            }
2640        }
2641    }
2642    
2643  void MainWindow::on_action_remove_instrument() {  void MainWindow::on_action_remove_instrument() {
2644      if (!file) return;      if (!file) return;
2645      if (file_is_shared) {      if (file_is_shared) {
# Line 1316  void MainWindow::on_action_remove_instru Line 2654  void MainWindow::on_action_remove_instru
2654      }      }
2655    
2656      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
2657      Gtk::TreeModel::iterator it = sel->get_selected();      std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
2658      if (it) {      for (int r = rows.size() - 1; r >= 0; --r) {
2659            Gtk::TreeModel::iterator it = m_refTreeModel->get_iter(rows[r]);
2660            if (!it) continue;
2661          Gtk::TreeModel::Row row = *it;          Gtk::TreeModel::Row row = *it;
2662          gig::Instrument* instr = row[m_Columns.m_col_instr];          gig::Instrument* instr = row[m_Columns.m_col_instr];
2663          try {          try {
2664                Gtk::TreePath path(it);
2665                int index = path[0];
2666    
2667              // remove instrument from the gig file              // remove instrument from the gig file
2668              if (instr) file->DeleteInstrument(instr);              if (instr) file->DeleteInstrument(instr);
             // remove respective row from instruments tree view  
             m_refTreeModel->erase(it);  
2669              file_changed();              file_changed();
2670    
2671                remove_instrument_from_menu(index);
2672    
2673                // remove row from instruments tree view
2674                m_refTreeModel->erase(it);
2675                // update "Nr" column of all instrument rows
2676                {
2677                    int index = 0;
2678                    for (Gtk::TreeModel::iterator it = m_refTreeModel->children().begin();
2679                         it != m_refTreeModel->children().end(); ++it, ++index)
2680                    {
2681                        Gtk::TreeModel::Row row = *it;
2682                        row[m_Columns.m_col_nr] = index;
2683                    }
2684                }
2685    
2686    #if GTKMM_MAJOR_VERSION < 3
2687                // select another instrument (in gtk3 this is done
2688                // automatically)
2689                if (!m_refTreeModel->children().empty()) {
2690                    if (index == m_refTreeModel->children().size()) {
2691                        index--;
2692                    }
2693                    m_TreeView.get_selection()->select(
2694                        Gtk::TreePath(ToString(index)));
2695                }
2696    #endif
2697                instr_props_set_instrument();
2698                instr = get_instrument();
2699                if (instr) {
2700                    midiRules.set_instrument(instr);
2701                } else {
2702                    midiRules.hide();
2703                }
2704          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
2705              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
2706              msg.run();              msg.run();
# Line 1341  void MainWindow::on_action_sample_proper Line 2716  void MainWindow::on_action_sample_proper
2716      msg.run();      msg.run();
2717  }  }
2718    
2719    void MainWindow::on_action_add_script_group() {
2720        static int __script_indexer = 0;
2721        if (!file) return;
2722        gig::ScriptGroup* group = file->AddScriptGroup();
2723        group->Name = gig_from_utf8(_("Unnamed Group"));
2724        if (__script_indexer) group->Name += " " + ToString(__script_indexer);
2725        __script_indexer++;
2726        // update sample tree view
2727        Gtk::TreeModel::iterator iterGroup = m_refScriptsTreeModel->append();
2728        Gtk::TreeModel::Row rowGroup = *iterGroup;
2729        rowGroup[m_ScriptsModel.m_col_name] = gig_to_utf8(group->Name);
2730        rowGroup[m_ScriptsModel.m_col_script] = NULL;
2731        rowGroup[m_ScriptsModel.m_col_group] = group;
2732        file_changed();
2733    }
2734    
2735    void MainWindow::on_action_add_script() {
2736        if (!file) return;
2737        // get selected group
2738        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewScripts.get_selection();
2739        Gtk::TreeModel::iterator it = sel->get_selected();
2740        if (!it) return;
2741        Gtk::TreeModel::Row row = *it;
2742        gig::ScriptGroup* group = row[m_ScriptsModel.m_col_group];
2743        if (!group) { // not a group, but a script is selected (probably)
2744            gig::Script* script = row[m_ScriptsModel.m_col_script];
2745            if (!script) return;
2746            it = row.parent(); // resolve parent (that is the script's group)
2747            if (!it) return;
2748            row = *it;
2749            group = row[m_ScriptsModel.m_col_group];
2750            if (!group) return;
2751        }
2752    
2753        // add a new script to the .gig file
2754        gig::Script* script = group->AddScript();    
2755        Glib::ustring name = _("Unnamed Script");
2756        script->Name = gig_from_utf8(name);
2757    
2758        // add script to the tree view
2759        Gtk::TreeModel::iterator iterScript =
2760            m_refScriptsTreeModel->append(row.children());
2761        Gtk::TreeModel::Row rowScript = *iterScript;
2762        rowScript[m_ScriptsModel.m_col_name] = name;
2763        rowScript[m_ScriptsModel.m_col_script] = script;
2764        rowScript[m_ScriptsModel.m_col_group]  = NULL;
2765    
2766        // unfold group of new script item in treeview
2767        Gtk::TreeModel::Path path(iterScript);
2768        m_TreeViewScripts.expand_to_path(path);
2769    }
2770    
2771    void MainWindow::on_action_edit_script() {
2772        if (!file) return;
2773        // get selected script
2774        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewScripts.get_selection();
2775        Gtk::TreeModel::iterator it = sel->get_selected();
2776        if (!it) return;
2777        Gtk::TreeModel::Row row = *it;
2778        gig::Script* script = row[m_ScriptsModel.m_col_script];
2779        if (!script) return;
2780    
2781        ScriptEditor* editor = new ScriptEditor;
2782        editor->signal_script_to_be_changed.connect(
2783            signal_script_to_be_changed.make_slot()
2784        );
2785        editor->signal_script_changed.connect(
2786            signal_script_changed.make_slot()
2787        );
2788        editor->setScript(script);
2789        //editor->reparent(*this);
2790        editor->show();
2791    }
2792    
2793    void MainWindow::on_action_remove_script() {
2794        if (!file) return;
2795        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewScripts.get_selection();
2796        Gtk::TreeModel::iterator it = sel->get_selected();
2797        if (it) {
2798            Gtk::TreeModel::Row row = *it;
2799            gig::ScriptGroup* group = row[m_ScriptsModel.m_col_group];
2800            gig::Script* script     = row[m_ScriptsModel.m_col_script];
2801            Glib::ustring name      = row[m_ScriptsModel.m_col_name];
2802            try {
2803                // remove script group or script from the gig file
2804                if (group) {
2805                    // notify everybody that we're going to remove these samples
2806    //TODO:         scripts_to_be_removed_signal.emit(members);
2807                    // delete the group in the .gig file including the
2808                    // samples that belong to the group
2809                    file->DeleteScriptGroup(group);
2810                    // notify that we're done with removal
2811    //TODO:         scripts_removed_signal.emit();
2812                    file_changed();
2813                } else if (script) {
2814                    // notify everybody that we're going to remove this sample
2815    //TODO:         std::list<gig::Script*> lscripts;
2816    //TODO:         lscripts.push_back(script);
2817    //TODO:         scripts_to_be_removed_signal.emit(lscripts);
2818                    // remove sample from the .gig file
2819                    script->GetGroup()->DeleteScript(script);
2820                    // notify that we're done with removal
2821    //TODO:         scripts_removed_signal.emit();
2822                    dimreg_changed();
2823                    file_changed();
2824                }
2825                // remove respective row(s) from samples tree view
2826                m_refScriptsTreeModel->erase(it);
2827            } catch (RIFF::Exception e) {
2828                // pretend we're done with removal (i.e. to avoid dead locks)
2829    //TODO:     scripts_removed_signal.emit();
2830                // show error message
2831                Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
2832                msg.run();
2833            }
2834        }
2835    }
2836    
2837  void MainWindow::on_action_add_group() {  void MainWindow::on_action_add_group() {
2838      static int __sample_indexer = 0;      static int __sample_indexer = 0;
2839      if (!file) return;      if (!file) return;
2840      gig::Group* group = file->AddGroup();      gig::Group* group = file->AddGroup();
2841      group->Name = _("Unnamed Group");      group->Name = gig_from_utf8(_("Unnamed Group"));
2842      if (__sample_indexer) group->Name += " " + ToString(__sample_indexer);      if (__sample_indexer) group->Name += " " + ToString(__sample_indexer);
2843      __sample_indexer++;      __sample_indexer++;
2844      // update sample tree view      // update sample tree view
2845      Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();      Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
2846      Gtk::TreeModel::Row rowGroup = *iterGroup;      Gtk::TreeModel::Row rowGroup = *iterGroup;
2847      rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();      rowGroup[m_SamplesModel.m_col_name] = gig_to_utf8(group->Name);
2848      rowGroup[m_SamplesModel.m_col_sample] = NULL;      rowGroup[m_SamplesModel.m_col_sample] = NULL;
2849      rowGroup[m_SamplesModel.m_col_group] = group;      rowGroup[m_SamplesModel.m_col_group] = group;
2850      file_changed();      file_changed();
2851  }  }
2852    
2853    void MainWindow::on_action_replace_sample() {
2854        add_or_replace_sample(true);
2855    }
2856    
2857  void MainWindow::on_action_add_sample() {  void MainWindow::on_action_add_sample() {
2858        add_or_replace_sample(false);
2859    }
2860    
2861    void MainWindow::add_or_replace_sample(bool replace) {
2862      if (!file) return;      if (!file) return;
2863      // get selected group  
2864        // get selected group (and probably selected sample)
2865      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
2866      Gtk::TreeModel::iterator it = sel->get_selected();      std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
2867        if (rows.empty()) return;
2868        Gtk::TreeModel::iterator it = m_refSamplesTreeModel->get_iter(rows[0]);
2869      if (!it) return;      if (!it) return;
2870      Gtk::TreeModel::Row row = *it;      Gtk::TreeModel::Row row = *it;
2871        gig::Sample* sample = NULL;
2872      gig::Group* group = row[m_SamplesModel.m_col_group];      gig::Group* group = row[m_SamplesModel.m_col_group];
2873      if (!group) { // not a group, but a sample is selected (probably)      if (!group) { // not a group, but a sample is selected (probably)
2874          gig::Sample* sample = row[m_SamplesModel.m_col_sample];          if (replace) sample = row[m_SamplesModel.m_col_sample];
2875          if (!sample) return;          if (!row[m_SamplesModel.m_col_sample]) return;
2876          it = row.parent(); // resolve parent (that is the sample's group)          it = row.parent(); // resolve parent (that is the sample's group)
2877          if (!it) return;          if (!it) return;
2878          row = *it;          if (!replace) row = *it;
2879          group = row[m_SamplesModel.m_col_group];          group = (*it)[m_SamplesModel.m_col_group];
2880          if (!group) return;          if (!group) return;
2881      }      }
2882        if (replace && !sample) return;
2883    
2884      // show 'browse for file' dialog      // show 'browse for file' dialog
2885      Gtk::FileChooserDialog dialog(*this, _("Add Sample(s)"));      Gtk::FileChooserDialog dialog(*this, replace ? _("Replace Sample with") : _("Add Sample(s)"));
2886      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2887      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
2888      dialog.set_select_multiple(true);      dialog.set_select_multiple(!replace); // allow multi audio file selection only when adding new samples, does not make sense when replacing a specific sample
2889      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile  
2890        // matches all file types supported by libsndfile
2891    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
2892        Gtk::FileFilter soundfilter;
2893    #else
2894        Glib::RefPtr<Gtk::FileFilter> soundfilter = Gtk::FileFilter::create();
2895    #endif
2896      const char* const supportedFileTypes[] = {      const char* const supportedFileTypes[] = {
2897          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
2898          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
# Line 1387  void MainWindow::on_action_add_sample() Line 2900  void MainWindow::on_action_add_sample()
2900          "*.W64", "*.pvf", "*.PVF", "*.xi", "*.XI", "*.htk", "*.HTK",          "*.W64", "*.pvf", "*.PVF", "*.xi", "*.XI", "*.htk", "*.HTK",
2901          "*.caf", "*.CAF", NULL          "*.caf", "*.CAF", NULL
2902      };      };
2903        const char* soundfiles = _("Sound Files");
2904        const char* allfiles = _("All Files");
2905    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
2906      for (int i = 0; supportedFileTypes[i]; i++)      for (int i = 0; supportedFileTypes[i]; i++)
2907          soundfilter.add_pattern(supportedFileTypes[i]);          soundfilter.add_pattern(supportedFileTypes[i]);
2908      soundfilter.set_name(_("Sound Files"));      soundfilter.set_name(soundfiles);
2909      Gtk::FileFilter allpassfilter; // matches every file  
2910        // matches every file
2911        Gtk::FileFilter allpassfilter;
2912      allpassfilter.add_pattern("*.*");      allpassfilter.add_pattern("*.*");
2913      allpassfilter.set_name(_("All Files"));      allpassfilter.set_name(allfiles);
2914    #else
2915        for (int i = 0; supportedFileTypes[i]; i++)
2916            soundfilter->add_pattern(supportedFileTypes[i]);
2917        soundfilter->set_name(soundfiles);
2918    
2919        // matches every file
2920        Glib::RefPtr<Gtk::FileFilter> allpassfilter = Gtk::FileFilter::create();
2921        allpassfilter->add_pattern("*.*");
2922        allpassfilter->set_name(allfiles);
2923    #endif
2924      dialog.add_filter(soundfilter);      dialog.add_filter(soundfilter);
2925      dialog.add_filter(allpassfilter);      dialog.add_filter(allpassfilter);
2926      if (current_sample_dir != "") {      if (current_sample_dir != "") {
# Line 1401  void MainWindow::on_action_add_sample() Line 2929  void MainWindow::on_action_add_sample()
2929      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
2930          current_sample_dir = dialog.get_current_folder();          current_sample_dir = dialog.get_current_folder();
2931          Glib::ustring error_files;          Glib::ustring error_files;
2932          Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();          std::vector<std::string> filenames = dialog.get_filenames();
2933          for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin();          for (std::vector<std::string>::iterator iter = filenames.begin();
2934               iter != filenames.end(); ++iter) {               iter != filenames.end(); ++iter) {
2935              printf("Adding sample %s\n",(*iter).c_str());              printf("Adding sample %s\n",(*iter).c_str());
2936              // use libsndfile to retrieve file informations              // use libsndfile to retrieve file informations
# Line 1428  void MainWindow::on_action_add_sample() Line 2956  void MainWindow::on_action_add_sample()
2956                          sf_close(hFile); // close sound file                          sf_close(hFile); // close sound file
2957                          throw std::string(_("format not supported")); // unsupported subformat (yet?)                          throw std::string(_("format not supported")); // unsupported subformat (yet?)
2958                  }                  }
2959                  // add a new sample to the .gig file                  // add a new sample to the .gig file (if adding is requested actually)
2960                  gig::Sample* sample = file->AddSample();                  if (!replace) sample = file->AddSample();
2961                  // file name without path                  // file name without path
2962                  Glib::ustring filename = Glib::filename_display_basename(*iter);                  Glib::ustring filename = Glib::filename_display_basename(*iter);
2963                  // remove file extension if there is one                  // remove file extension if there is one
# Line 1439  void MainWindow::on_action_add_sample() Line 2967  void MainWindow::on_action_add_sample()
2967                          break;                          break;
2968                      }                      }
2969                  }                  }
2970                  sample->pInfo->Name = filename;                  sample->pInfo->Name = gig_from_utf8(filename);
2971                  sample->Channels = info.channels;                  sample->Channels = info.channels;
2972                  sample->BitDepth = bitdepth;                  sample->BitDepth = bitdepth;
2973                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
# Line 1453  void MainWindow::on_action_add_sample() Line 2981  void MainWindow::on_action_add_sample()
2981                                 &instrument, sizeof(instrument)) != SF_FALSE)                                 &instrument, sizeof(instrument)) != SF_FALSE)
2982                  {                  {
2983                      sample->MIDIUnityNote = instrument.basenote;                      sample->MIDIUnityNote = instrument.basenote;
2984                        sample->FineTune      = instrument.detune;
2985    
 #if HAVE_SF_INSTRUMENT_LOOPS  
2986                      if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {                      if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
2987                          sample->Loops = 1;                          sample->Loops = 1;
2988    
# Line 1474  void MainWindow::on_action_add_sample() Line 3002  void MainWindow::on_action_add_sample()
3002                          sample->LoopPlayCount = instrument.loops[0].count;                          sample->LoopPlayCount = instrument.loops[0].count;
3003                          sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;                          sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
3004                      }                      }
 #endif  
3005                  }                  }
3006    
3007                  // schedule resizing the sample (which will be done                  // schedule resizing the sample (which will be done
3008                  // physically when File::Save() is called)                  // physically when File::Save() is called)
3009                  sample->Resize(info.frames);                  sample->Resize(info.frames);
3010                  // make sure sample is part of the selected group                  // make sure sample is part of the selected group
3011                  group->AddSample(sample);                  if (!replace) group->AddSample(sample);
3012                  // schedule that physical resize and sample import                  // schedule that physical resize and sample import
3013                  // (data copying), performed when "Save" is requested                  // (data copying), performed when "Save" is requested
3014                  SampleImportItem sched_item;                  SampleImportItem sched_item;
3015                  sched_item.gig_sample  = sample;                  sched_item.gig_sample  = sample;
3016                  sched_item.sample_path = *iter;                  sched_item.sample_path = *iter;
3017                  m_SampleImportQueue.push_back(sched_item);                  m_SampleImportQueue[sample] = sched_item;
3018                  // add sample to the tree view                  // add sample to the tree view
3019                  Gtk::TreeModel::iterator iterSample =                  if (replace) {
3020                      m_refSamplesTreeModel->append(row.children());                      row[m_SamplesModel.m_col_name] = gig_to_utf8(sample->pInfo->Name);
3021                  Gtk::TreeModel::Row rowSample = *iterSample;                  } else {
3022                  rowSample[m_SamplesModel.m_col_name]   = filename;                      Gtk::TreeModel::iterator iterSample =
3023                  rowSample[m_SamplesModel.m_col_sample] = sample;                          m_refSamplesTreeModel->append(row.children());
3024                  rowSample[m_SamplesModel.m_col_group]  = NULL;                      Gtk::TreeModel::Row rowSample = *iterSample;
3025                        rowSample[m_SamplesModel.m_col_name] =
3026                            gig_to_utf8(sample->pInfo->Name);
3027                        rowSample[m_SamplesModel.m_col_sample] = sample;
3028                        rowSample[m_SamplesModel.m_col_group]  = NULL;
3029                    }
3030                  // close sound file                  // close sound file
3031                  sf_close(hFile);                  sf_close(hFile);
3032                  file_changed();                  file_changed();
3033              } 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)
3034                  if (error_files.size()) error_files += "\n";                  if (!error_files.empty()) error_files += "\n";
3035                  error_files += *iter += " (" + what + ")";                  error_files += *iter += " (" + what + ")";
3036              }              }
3037          }          }
3038          // 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
3039          if (error_files.size()) {          if (!error_files.empty()) {
3040              Glib::ustring txt = _("Could not add the following sample(s):\n") + error_files;              Glib::ustring txt =
3041                    (replace
3042                        ? _("Failed to replace sample with:\n")
3043                        : _("Could not add the following sample(s):\n"))
3044                    + error_files;
3045              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
3046              msg.run();              msg.run();
3047          }          }
# Line 1517  void MainWindow::on_action_replace_all_s Line 3053  void MainWindow::on_action_replace_all_s
3053      if (!file) return;      if (!file) return;
3054      Gtk::FileChooserDialog dialog(*this, _("Select Folder"),      Gtk::FileChooserDialog dialog(*this, _("Select Folder"),
3055                                    Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);                                    Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
3056      view::WrapLabel description(      const char* str =
3057          _("This is a very specific function. It tries to replace all samples "          _("This is a very specific function. It tries to replace all samples "
3058            "in the current gig file by samples located in the chosen "            "in the current gig file by samples located in the chosen "
3059            "directory.\n\n"            "directory.\n\n"
# Line 1531  void MainWindow::on_action_replace_all_s Line 3067  void MainWindow::on_action_replace_all_s
3067            "the sample in the gig file accordingly. If you don't need an "            "the sample in the gig file accordingly. If you don't need an "
3068            "extension, blank the field below. Any gig sample where no "            "extension, blank the field below. Any gig sample where no "
3069            "appropriate sample file could be found will be reported and left "            "appropriate sample file could be found will be reported and left "
3070            "untouched.\n")            "untouched.\n");
3071      );  #if GTKMM_MAJOR_VERSION < 3
3072        view::WrapLabel description(str);
3073    #else
3074        Gtk::Label description(str);
3075        description.set_line_wrap();
3076    #endif
3077      Gtk::HBox entryArea;      Gtk::HBox entryArea;
3078      Gtk::Label entryLabel( _("Add filename extension: "), Gtk::ALIGN_RIGHT);      Gtk::Label entryLabel( _("Add filename extension: "), Gtk::ALIGN_START);
3079      Gtk::Entry postfixEntryBox;      Gtk::Entry postfixEntryBox;
3080      postfixEntryBox.set_text(".wav");      postfixEntryBox.set_text(".wav");
3081      entryArea.pack_start(entryLabel);      entryArea.pack_start(entryLabel);
# Line 1553  void MainWindow::on_action_replace_all_s Line 3094  void MainWindow::on_action_replace_all_s
3094      {      {
3095          current_sample_dir = dialog.get_current_folder();          current_sample_dir = dialog.get_current_folder();
3096          Glib::ustring error_files;          Glib::ustring error_files;
3097          Glib::ustring folder = dialog.get_filename();          std::string folder = dialog.get_filename();
3098          for (gig::Sample* sample = file->GetFirstSample();          for (gig::Sample* sample = file->GetFirstSample();
3099               sample; sample = file->GetNextSample())               sample; sample = file->GetNextSample())
3100          {          {
3101              std::string filename =              std::string filename =
3102                  folder + G_DIR_SEPARATOR_S + sample->pInfo->Name +                  folder + G_DIR_SEPARATOR_S +
3103                  postfixEntryBox.get_text().raw();                  Glib::filename_from_utf8(gig_to_utf8(sample->pInfo->Name) +
3104                                             postfixEntryBox.get_text());
3105              SF_INFO info;              SF_INFO info;
3106              info.format = 0;              info.format = 0;
3107              SNDFILE* hFile = sf_open(filename.c_str(), SFM_READ, &info);              SNDFILE* hFile = sf_open(filename.c_str(), SFM_READ, &info);
3108              try              try
3109              {              {
3110                  if (!hFile) throw std::string(_("could not open file"));                  if (!hFile) throw std::string(_("could not open file"));
                 int bitdepth;  
3111                  switch (info.format & 0xff) {                  switch (info.format & 0xff) {
3112                      case SF_FORMAT_PCM_S8:                      case SF_FORMAT_PCM_S8:
3113                      case SF_FORMAT_PCM_16:                      case SF_FORMAT_PCM_16:
3114                      case SF_FORMAT_PCM_U8:                      case SF_FORMAT_PCM_U8:
                         bitdepth = 16;  
                         break;  
3115                      case SF_FORMAT_PCM_24:                      case SF_FORMAT_PCM_24:
3116                      case SF_FORMAT_PCM_32:                      case SF_FORMAT_PCM_32:
3117                      case SF_FORMAT_FLOAT:                      case SF_FORMAT_FLOAT:
3118                      case SF_FORMAT_DOUBLE:                      case SF_FORMAT_DOUBLE:
                         bitdepth = 24;  
3119                          break;                          break;
3120                      default:                      default:
3121                          sf_close(hFile);                          sf_close(hFile);
# Line 1586  void MainWindow::on_action_replace_all_s Line 3124  void MainWindow::on_action_replace_all_s
3124                  SampleImportItem sched_item;                  SampleImportItem sched_item;
3125                  sched_item.gig_sample  = sample;                  sched_item.gig_sample  = sample;
3126                  sched_item.sample_path = filename;                  sched_item.sample_path = filename;
3127                  m_SampleImportQueue.push_back(sched_item);                  m_SampleImportQueue[sample] = sched_item;
3128                  sf_close(hFile);                  sf_close(hFile);
3129                  file_changed();                  file_changed();
3130              }              }
3131              catch (std::string what)              catch (std::string what)
3132              {              {
3133                  if (error_files.size()) error_files += "\n";                  if (!error_files.empty()) error_files += "\n";
3134                      error_files += filename += " (" + what + ")";                  error_files += Glib::filename_to_utf8(filename) +
3135                        " (" + what + ")";
3136              }              }
3137          }          }
3138          // 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
3139          if (error_files.size()) {          if (!error_files.empty()) {
3140              Glib::ustring txt =              Glib::ustring txt =
3141                  _("Could not replace the following sample(s):\n") + error_files;                  _("Could not replace the following sample(s):\n") + error_files;
3142              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
# Line 1609  void MainWindow::on_action_replace_all_s Line 3148  void MainWindow::on_action_replace_all_s
3148  void MainWindow::on_action_remove_sample() {  void MainWindow::on_action_remove_sample() {
3149      if (!file) return;      if (!file) return;
3150      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
3151      Gtk::TreeModel::iterator it = sel->get_selected();      std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
3152      if (it) {      for (int r = rows.size() - 1; r >= 0; --r) {
3153            Gtk::TreeModel::iterator it = m_refSamplesTreeModel->get_iter(rows[r]);
3154            if (!it) continue;
3155          Gtk::TreeModel::Row row = *it;          Gtk::TreeModel::Row row = *it;
3156          gig::Group* group   = row[m_SamplesModel.m_col_group];          gig::Group* group   = row[m_SamplesModel.m_col_group];
3157          gig::Sample* sample = row[m_SamplesModel.m_col_sample];          gig::Sample* sample = row[m_SamplesModel.m_col_sample];
# Line 1618  void MainWindow::on_action_remove_sample Line 3159  void MainWindow::on_action_remove_sample
3159          try {          try {
3160              // remove group or sample from the gig file              // remove group or sample from the gig file
3161              if (group) {              if (group) {
3162                  // temporarily remember the samples that bolong to                  // temporarily remember the samples that belong to
3163                  // that group (we need that to clean the queue)                  // that group (we need that to clean the queue)
3164                  std::list<gig::Sample*> members;                  std::list<gig::Sample*> members;
3165                  for (gig::Sample* pSample = group->GetFirstSample();                  for (gig::Sample* pSample = group->GetFirstSample();
# Line 1635  void MainWindow::on_action_remove_sample Line 3176  void MainWindow::on_action_remove_sample
3176                  // if sample(s) were just previously added, remove                  // if sample(s) were just previously added, remove
3177                  // them from the import queue                  // them from the import queue
3178                  for (std::list<gig::Sample*>::iterator member = members.begin();                  for (std::list<gig::Sample*>::iterator member = members.begin();
3179                       member != members.end(); ++member) {                       member != members.end(); ++member)
3180                      for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();                  {
3181                           iter != m_SampleImportQueue.end(); ++iter) {                      if (m_SampleImportQueue.count(*member)) {
3182                          if ((*iter).gig_sample == *member) {                          printf("Removing previously added sample '%s' from group '%s'\n",
3183                              printf("Removing previously added sample '%s' from group '%s'\n",                                 m_SampleImportQueue[sample].sample_path.c_str(), name.c_str());
3184                                     (*iter).sample_path.c_str(), name.c_str());                          m_SampleImportQueue.erase(*member);
                             m_SampleImportQueue.erase(iter);  
                             break;  
                         }  
3185                      }                      }
3186                  }                  }
3187                  file_changed();                  file_changed();
# Line 1658  void MainWindow::on_action_remove_sample Line 3196  void MainWindow::on_action_remove_sample
3196                  samples_removed_signal.emit();                  samples_removed_signal.emit();
3197                  // if sample was just previously added, remove it from                  // if sample was just previously added, remove it from
3198                  // the import queue                  // the import queue
3199                  for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();                  if (m_SampleImportQueue.count(sample)) {
3200                       iter != m_SampleImportQueue.end(); ++iter) {                      printf("Removing previously added sample '%s'\n",
3201                      if ((*iter).gig_sample == sample) {                             m_SampleImportQueue[sample].sample_path.c_str());
3202                          printf("Removing previously added sample '%s'\n",                      m_SampleImportQueue.erase(sample);
                                (*iter).sample_path.c_str());  
                         m_SampleImportQueue.erase(iter);  
                         break;  
                     }  
3203                  }                  }
3204                  dimreg_changed();                  dimreg_changed();
3205                  file_changed();                  file_changed();
# Line 1682  void MainWindow::on_action_remove_sample Line 3216  void MainWindow::on_action_remove_sample
3216      }      }
3217  }  }
3218    
3219    void MainWindow::on_action_remove_unused_samples() {
3220        if (!file) return;
3221    
3222        // collect all samples that are not referenced by any instrument
3223        std::list<gig::Sample*> lsamples;
3224        for (int iSample = 0; file->GetSample(iSample); ++iSample) {
3225            gig::Sample* sample = file->GetSample(iSample);
3226            bool isUsed = false;
3227            for (gig::Instrument* instrument = file->GetFirstInstrument(); instrument;
3228                                  instrument = file->GetNextInstrument())
3229            {
3230                for (gig::Region* rgn = instrument->GetFirstRegion(); rgn;
3231                                  rgn = instrument->GetNextRegion())
3232                {
3233                    for (int i = 0; i < 256; ++i) {
3234                        if (!rgn->pDimensionRegions[i]) continue;
3235                        if (rgn->pDimensionRegions[i]->pSample != sample) continue;
3236                        isUsed = true;
3237                        goto endOfRefSearch;
3238                    }
3239                }
3240            }
3241            endOfRefSearch:
3242            if (!isUsed) lsamples.push_back(sample);
3243        }
3244    
3245        if (lsamples.empty()) return;
3246    
3247        // notify everybody that we're going to remove these samples
3248        samples_to_be_removed_signal.emit(lsamples);
3249    
3250        // remove collected samples
3251        try {
3252            for (std::list<gig::Sample*>::iterator itSample = lsamples.begin();
3253                 itSample != lsamples.end(); ++itSample)
3254            {
3255                gig::Sample* sample = *itSample;
3256                // remove sample from the .gig file
3257                file->DeleteSample(sample);
3258                // if sample was just previously added, remove it from the import queue
3259                if (m_SampleImportQueue.count(sample)) {
3260                    printf("Removing previously added sample '%s'\n",
3261                           m_SampleImportQueue[sample].sample_path.c_str());
3262                    m_SampleImportQueue.erase(sample);
3263                }
3264            }
3265        } catch (RIFF::Exception e) {
3266            // show error message
3267            Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
3268            msg.run();
3269        }
3270    
3271        // notify everybody that we're done with removal
3272        samples_removed_signal.emit();
3273    
3274        dimreg_changed();
3275        file_changed();
3276        __refreshEntireGUI();
3277    }
3278    
3279    // see comment on on_sample_treeview_drag_begin()
3280    void MainWindow::on_scripts_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
3281    {
3282        first_call_to_drag_data_get = true;
3283    }
3284    
3285    void MainWindow::on_scripts_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,
3286                                                       Gtk::SelectionData& selection_data, guint, guint)
3287    {
3288        if (!first_call_to_drag_data_get) return;
3289        first_call_to_drag_data_get = false;
3290    
3291        // get selected script
3292        gig::Script* script = NULL;
3293        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewScripts.get_selection();
3294        Gtk::TreeModel::iterator it = sel->get_selected();
3295        if (it) {
3296            Gtk::TreeModel::Row row = *it;
3297            script = row[m_ScriptsModel.m_col_script];
3298        }
3299        // pass the gig::Script as pointer
3300        selection_data.set(selection_data.get_target(), 0/*unused*/,
3301                           (const guchar*)&script,
3302                           sizeof(script)/*length of data in bytes*/);
3303    }
3304    
3305    // see comment on on_sample_treeview_drag_begin()
3306    void MainWindow::on_instruments_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
3307    {
3308        first_call_to_drag_data_get = true;
3309    }
3310    
3311    void MainWindow::on_instruments_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,
3312                                                           Gtk::SelectionData& selection_data, guint, guint)
3313    {
3314        if (!first_call_to_drag_data_get) return;
3315        first_call_to_drag_data_get = false;
3316    
3317        // get selected source instrument
3318        gig::Instrument* src = NULL;
3319        {
3320            Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
3321            std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
3322            if (!rows.empty()) {
3323                Gtk::TreeModel::iterator it = m_refTreeModel->get_iter(rows[0]);
3324                if (it) {
3325                    Gtk::TreeModel::Row row = *it;
3326                    src = row[m_Columns.m_col_instr];
3327                }
3328            }
3329        }
3330        if (!src) return;
3331    
3332        // pass the source gig::Instrument as pointer
3333        selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&src,
3334                           sizeof(src)/*length of data in bytes*/);
3335    }
3336    
3337    void MainWindow::on_instruments_treeview_drop_drag_data_received(
3338        const Glib::RefPtr<Gdk::DragContext>& context, int x, int y,
3339        const Gtk::SelectionData& selection_data, guint, guint time)
3340    {
3341        gig::Instrument* src = *((gig::Instrument**) selection_data.get_data());
3342        if (!src || selection_data.get_length() != sizeof(gig::Instrument*))
3343            return;
3344    
3345        gig::Instrument* dst = NULL;
3346        {
3347            Gtk::TreeModel::Path path;
3348            const bool found = m_TreeView.get_path_at_pos(x, y, path);
3349            if (!found) return;
3350    
3351            Gtk::TreeModel::iterator iter = m_refTreeModel->get_iter(path);
3352            if (!iter) return;
3353            Gtk::TreeModel::Row row = *iter;
3354            dst = row[m_Columns.m_col_instr];
3355        }
3356        if (!dst) return;
3357    
3358        //printf("dragdrop received src=%s dst=%s\n", src->pInfo->Name.c_str(), dst->pInfo->Name.c_str());
3359        src->MoveTo(dst);
3360        __refreshEntireGUI();
3361        select_instrument(src);
3362    }
3363    
3364  // For some reason drag_data_get gets called two times for each  // For some reason drag_data_get gets called two times for each
3365  // drag'n'drop (at least when target is an Entry). This work-around  // drag'n'drop (at least when target is an Entry). This work-around
3366  // makes sure the code in drag_data_get and drop_drag_data_received is  // makes sure the code in drag_data_get and drop_drag_data_received is
# Line 1700  void MainWindow::on_sample_treeview_drag Line 3379  void MainWindow::on_sample_treeview_drag
3379      // get selected sample      // get selected sample
3380      gig::Sample* sample = NULL;      gig::Sample* sample = NULL;
3381      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
3382      Gtk::TreeModel::iterator it = sel->get_selected();      std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
3383      if (it) {      if (!rows.empty()) {
3384          Gtk::TreeModel::Row row = *it;          Gtk::TreeModel::iterator it = m_refSamplesTreeModel->get_iter(rows[0]);
3385          sample = row[m_SamplesModel.m_col_sample];          if (it) {
3386                Gtk::TreeModel::Row row = *it;
3387                sample = row[m_SamplesModel.m_col_sample];
3388            }
3389      }      }
3390      // pass the gig::Sample as pointer      // pass the gig::Sample as pointer
3391      selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&sample,      selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&sample,
# Line 1740  void MainWindow::on_sample_label_drop_dr Line 3422  void MainWindow::on_sample_label_drop_dr
3422          bool channels_changed = false;          bool channels_changed = false;
3423          if (sample->Channels == 1 && stereo_dimension) {          if (sample->Channels == 1 && stereo_dimension) {
3424              // remove the samplechannel dimension              // remove the samplechannel dimension
3425    /* commented out, because it makes it impossible building up an instrument from scratch using two separate L/R samples
3426              region->DeleteDimension(stereo_dimension);              region->DeleteDimension(stereo_dimension);
3427              channels_changed = true;              channels_changed = true;
3428              region_changed();              region_changed();
3429    */
3430          }          }
3431          dimreg_edit.set_sample(sample);          dimreg_edit.set_sample(
3432                sample,
3433                is_copy_samples_unity_note_enabled(),
3434                is_copy_samples_fine_tune_enabled(),
3435                is_copy_samples_loop_enabled()
3436            );
3437    
3438          if (sample->Channels == 2 && !stereo_dimension) {          if (sample->Channels == 2 && !stereo_dimension) {
3439              // add samplechannel dimension              // add samplechannel dimension
# Line 1787  void MainWindow::sample_name_changed(con Line 3476  void MainWindow::sample_name_changed(con
3476      Glib::ustring name  = row[m_SamplesModel.m_col_name];      Glib::ustring name  = row[m_SamplesModel.m_col_name];
3477      gig::Group* group   = row[m_SamplesModel.m_col_group];      gig::Group* group   = row[m_SamplesModel.m_col_group];
3478      gig::Sample* sample = row[m_SamplesModel.m_col_sample];      gig::Sample* sample = row[m_SamplesModel.m_col_sample];
3479        gig::String gigname(gig_from_utf8(name));
3480      if (group) {      if (group) {
3481          if (group->Name != name) {          if (group->Name != gigname) {
3482              group->Name = name;              group->Name = gigname;
3483              printf("group name changed\n");              printf("group name changed\n");
3484              file_changed();              file_changed();
3485          }          }
3486      } else if (sample) {      } else if (sample) {
3487          if (sample->pInfo->Name != name.raw()) {          if (sample->pInfo->Name != gigname) {
3488              sample->pInfo->Name = name.raw();              sample->pInfo->Name = gigname;
3489              printf("sample name changed\n");              printf("sample name changed\n");
3490              file_changed();              file_changed();
3491          }          }
3492      }      }
3493  }  }
3494    
3495    void MainWindow::script_name_changed(const Gtk::TreeModel::Path& path,
3496                                         const Gtk::TreeModel::iterator& iter) {
3497        if (!iter) return;
3498        Gtk::TreeModel::Row row = *iter;
3499        Glib::ustring name      = row[m_ScriptsModel.m_col_name];
3500        gig::ScriptGroup* group = row[m_ScriptsModel.m_col_group];
3501        gig::Script* script     = row[m_ScriptsModel.m_col_script];
3502        gig::String gigname(gig_from_utf8(name));
3503        if (group) {
3504            if (group->Name != gigname) {
3505                group->Name = gigname;
3506                printf("script group name changed\n");
3507                file_changed();
3508            }
3509        } else if (script) {
3510            if (script->Name != gigname) {
3511                script->Name = gigname;
3512                printf("script name changed\n");
3513                file_changed();
3514            }
3515        }
3516    }
3517    
3518    void MainWindow::script_double_clicked(const Gtk::TreeModel::Path& path,
3519                                           Gtk::TreeViewColumn* column)
3520    {
3521        Gtk::TreeModel::iterator iter = m_refScriptsTreeModel->get_iter(path);
3522        if (!iter) return;
3523        Gtk::TreeModel::Row row = *iter;
3524        gig::Script* script = row[m_ScriptsModel.m_col_script];
3525        if (!script) return;
3526    
3527        ScriptEditor* editor = new ScriptEditor;
3528        editor->signal_script_to_be_changed.connect(
3529            signal_script_to_be_changed.make_slot()
3530        );
3531        editor->signal_script_changed.connect(
3532            signal_script_changed.make_slot()
3533        );
3534        editor->setScript(script);
3535        //editor->reparent(*this);
3536        editor->show();
3537    }
3538    
3539  void MainWindow::instrument_name_changed(const Gtk::TreeModel::Path& path,  void MainWindow::instrument_name_changed(const Gtk::TreeModel::Path& path,
3540                                           const Gtk::TreeModel::iterator& iter) {                                           const Gtk::TreeModel::iterator& iter) {
3541      if (!iter) return;      if (!iter) return;
3542      Gtk::TreeModel::Row row = *iter;      Gtk::TreeModel::Row row = *iter;
3543      Glib::ustring name = row[m_Columns.m_col_name];      Glib::ustring name = row[m_Columns.m_col_name];
3544    
3545        // change name in instrument menu
3546        int index = path[0];
3547        const std::vector<Gtk::Widget*> children = instrument_menu->get_children();
3548        if (index < children.size()) {
3549    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 16) || GTKMM_MAJOR_VERSION > 2
3550            static_cast<Gtk::RadioMenuItem*>(children[index])->set_label(name);
3551    #else
3552            remove_instrument_from_menu(index);
3553            Gtk::RadioMenuItem* item = add_instrument_to_menu(name, index);
3554            item->set_active();
3555    #endif
3556        }
3557    
3558        // change name in gig
3559      gig::Instrument* instrument = row[m_Columns.m_col_instr];      gig::Instrument* instrument = row[m_Columns.m_col_instr];
3560      if (instrument && instrument->pInfo->Name != name.raw()) {      gig::String gigname(gig_from_utf8(name));
3561          instrument->pInfo->Name = name.raw();      if (instrument && instrument->pInfo->Name != gigname) {
3562            instrument->pInfo->Name = gigname;
3563    
3564            // change name in the instrument properties window
3565            if (instrumentProps.get_instrument() == instrument) {
3566                instrumentProps.update_name();
3567            }
3568    
3569          file_changed();          file_changed();
3570      }      }
3571  }  }
3572    
3573    void MainWindow::on_action_combine_instruments() {
3574        CombineInstrumentsDialog* d = new CombineInstrumentsDialog(*this, file);
3575        d->show_all();
3576        d->run();
3577        if (d->fileWasChanged()) {
3578            // update GUI with new instrument just created
3579            add_instrument(d->newCombinedInstrument());
3580        }
3581        delete d;
3582    }
3583    
3584    void MainWindow::on_action_view_references() {
3585        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
3586        std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
3587        if (rows.empty()) return;
3588        Gtk::TreeModel::iterator it = m_refSamplesTreeModel->get_iter(rows[0]);
3589        if (!it) return;
3590        Gtk::TreeModel::Row row = *it;
3591        gig::Sample* sample = row[m_SamplesModel.m_col_sample];
3592        if (!sample) return;
3593    
3594        ReferencesView* d = new ReferencesView(*this);
3595        d->setSample(sample);
3596        d->dimension_region_selected.connect(
3597            sigc::mem_fun(*this, &MainWindow::select_dimension_region)
3598        );
3599        d->show_all();
3600        d->resize(500, 400);
3601        d->run();
3602        delete d;
3603    }
3604    
3605    void MainWindow::mergeFiles(const std::vector<std::string>& filenames) {
3606        struct _Source {
3607            std::vector<RIFF::File*> riffs;
3608            std::vector<gig::File*> gigs;
3609            
3610            ~_Source() {
3611                for (int k = 0; k < gigs.size(); ++k) delete gigs[k];
3612                for (int k = 0; k < riffs.size(); ++k) delete riffs[k];
3613                riffs.clear();
3614                gigs.clear();
3615            }
3616        } sources;
3617    
3618        if (filenames.empty())
3619            throw RIFF::Exception(_("No files selected, so nothing done."));
3620    
3621        // first open all input files (to avoid output file corruption)
3622        int i;
3623        try {
3624            for (i = 0; i < filenames.size(); ++i) {
3625                const std::string& filename = filenames[i];
3626                printf("opening file=%s\n", filename.c_str());
3627    
3628                RIFF::File* riff = new RIFF::File(filename);
3629                sources.riffs.push_back(riff);
3630    
3631                gig::File* gig = new gig::File(riff);
3632                sources.gigs.push_back(gig);
3633            }
3634        } catch (RIFF::Exception e) {
3635            throw RIFF::Exception(
3636                _("Error occurred while opening '") +
3637                filenames[i] +
3638                "': " +
3639                e.Message
3640            );
3641        } catch (...) {
3642            throw RIFF::Exception(
3643                _("Unknown exception occurred while opening '") +
3644                filenames[i] + "'"
3645            );
3646        }
3647    
3648        // now merge the opened .gig files to the main .gig file currently being
3649        // open in gigedit
3650        try {
3651            for (i = 0; i < filenames.size(); ++i) {
3652                const std::string& filename = filenames[i];
3653                printf("merging file=%s\n", filename.c_str());
3654                assert(i < sources.gigs.size());
3655    
3656                this->file->AddContentOf(sources.gigs[i]);
3657            }
3658        } catch (RIFF::Exception e) {
3659            throw RIFF::Exception(
3660                _("Error occurred while merging '") +
3661                filenames[i] +
3662                "': " +
3663                e.Message
3664            );
3665        } catch (...) {
3666            throw RIFF::Exception(
3667                _("Unknown exception occurred while merging '") +
3668                filenames[i] + "'"
3669            );
3670        }
3671    
3672        // Finally save gig file persistently to disk ...
3673        //NOTE: requires that this gig file already has a filename !
3674        {
3675            std::cout << "Saving file\n" << std::flush;
3676            file_structure_to_be_changed_signal.emit(this->file);
3677    
3678            progress_dialog = new ProgressDialog( //FIXME: memory leak!
3679                _("Saving") +  Glib::ustring(" '") +
3680                Glib::filename_display_basename(this->filename) + "' ...",
3681                *this
3682            );
3683            progress_dialog->show_all();
3684            saver = new Saver(this->file); //FIXME: memory leak!
3685            saver->signal_progress().connect(
3686                sigc::mem_fun(*this, &MainWindow::on_saver_progress));
3687            saver->signal_finished().connect(
3688                sigc::mem_fun(*this, &MainWindow::on_saver_finished));
3689            saver->signal_error().connect(
3690                sigc::mem_fun(*this, &MainWindow::on_saver_error));
3691            saver->launch();
3692        }
3693    }
3694    
3695    void MainWindow::on_action_merge_files() {
3696        if (this->file->GetFileName().empty()) {
3697            Glib::ustring txt = _(
3698                "You seem to have a new .gig file open that has not been saved "
3699                "yet. You must save it somewhere before starting to merge it with "
3700                "other .gig files though, because during the merge operation the "
3701                "other files' sample data must be written on file level to the "
3702                "target .gig file."
3703            );
3704            Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
3705            msg.run();
3706            return;
3707        }
3708    
3709        Gtk::FileChooserDialog dialog(*this, _("Merge .gig files"));
3710        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3711        dialog.add_button(_("Merge"), Gtk::RESPONSE_OK);
3712        dialog.set_default_response(Gtk::RESPONSE_CANCEL);
3713    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
3714        Gtk::FileFilter filter;
3715        filter.add_pattern("*.gig");
3716    #else
3717        Glib::RefPtr<Gtk::FileFilter> filter = Gtk::FileFilter::create();
3718        filter->add_pattern("*.gig");
3719    #endif
3720        dialog.set_filter(filter);
3721        if (current_gig_dir != "") {
3722            dialog.set_current_folder(current_gig_dir);
3723        }
3724        dialog.set_select_multiple(true);
3725    
3726        // show warning in the file picker dialog
3727        Gtk::HBox descriptionArea;
3728        descriptionArea.set_spacing(15);
3729        Gtk::Image warningIcon;
3730        warningIcon.set_from_icon_name("dialog-warning",
3731                                       Gtk::IconSize(Gtk::ICON_SIZE_DIALOG));
3732        descriptionArea.pack_start(warningIcon, Gtk::PACK_SHRINK);
3733    #if GTKMM_MAJOR_VERSION < 3
3734        view::WrapLabel description;
3735    #else
3736        Gtk::Label description;
3737        description.set_line_wrap();
3738    #endif
3739        description.set_markup(_(
3740            "\nSelect at least one .gig file that shall be merged to the .gig file "
3741            "currently being open in gigedit.\n\n"
3742            "<b>Please Note:</b> Merging with other files will modify your "
3743            "currently open .gig file on file level! And be aware that the current "
3744            "merge algorithm does not detect duplicate samples yet. So if you are "
3745            "merging files which are using equivalent sample data, those "
3746            "equivalent samples will currently be treated as separate samples and "
3747            "will accordingly be stored separately in the target .gig file!"
3748        ));
3749        descriptionArea.pack_start(description);
3750        dialog.get_vbox()->pack_start(descriptionArea, Gtk::PACK_SHRINK);
3751        descriptionArea.show_all();
3752    
3753        if (dialog.run() == Gtk::RESPONSE_OK) {
3754            printf("on_action_merge_files self=%p\n",
3755                   static_cast<void*>(Glib::Threads::Thread::self()));
3756            std::vector<std::string> filenames = dialog.get_filenames();
3757    
3758            // merge the selected files to the currently open .gig file
3759            try {
3760                mergeFiles(filenames);
3761            } catch (RIFF::Exception e) {
3762                Gtk::MessageDialog msg(*this, e.Message, false, Gtk::MESSAGE_ERROR);
3763                msg.run();
3764            }
3765    
3766            // update GUI
3767            __refreshEntireGUI();
3768        }
3769    }
3770    
3771  void MainWindow::set_file_is_shared(bool b) {  void MainWindow::set_file_is_shared(bool b) {
3772      this->file_is_shared = b;      this->file_is_shared = b;
3773    
# Line 1828  void MainWindow::set_file_is_shared(bool Line 3782  void MainWindow::set_file_is_shared(bool
3782              Gdk::Pixbuf::create_from_xpm_data(status_detached_xpm)              Gdk::Pixbuf::create_from_xpm_data(status_detached_xpm)
3783          );          );
3784      }      }
3785    
3786        {
3787            Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
3788                uiManager->get_widget("/MenuBar/MenuSettings/SyncSamplerInstrumentSelection"));
3789            if (item) item->set_sensitive(b);
3790        }
3791    }
3792    
3793    void MainWindow::on_sample_ref_count_incremented(gig::Sample* sample, int offset) {
3794        if (!sample) return;
3795        sample_ref_count[sample] += offset;
3796        const int refcount = sample_ref_count[sample];
3797    
3798        Glib::RefPtr<Gtk::TreeModel> model = m_TreeViewSamples.get_model();
3799        for (int g = 0; g < model->children().size(); ++g) {
3800            Gtk::TreeModel::Row rowGroup = model->children()[g];
3801            for (int s = 0; s < rowGroup.children().size(); ++s) {
3802                Gtk::TreeModel::Row rowSample = rowGroup.children()[s];
3803                if (rowSample[m_SamplesModel.m_col_sample] != sample) continue;
3804                rowSample[m_SamplesModel.m_col_refcount] = ToString(refcount) + " " + _("Refs.");
3805                rowSample[m_SamplesModel.m_color] = refcount ? "black" : "red";
3806            }
3807        }
3808    }
3809    
3810    void MainWindow::on_sample_ref_changed(gig::Sample* oldSample, gig::Sample* newSample) {
3811        on_sample_ref_count_incremented(oldSample, -1);
3812        on_sample_ref_count_incremented(newSample, +1);
3813    }
3814    
3815    void MainWindow::on_samples_to_be_removed(std::list<gig::Sample*> samples) {
3816        // just in case a new sample is added later with exactly the same memory
3817        // address, which would lead to incorrect refcount if not deleted here
3818        for (std::list<gig::Sample*>::const_iterator it = samples.begin();
3819             it != samples.end(); ++it)
3820        {
3821            sample_ref_count.erase(*it);
3822        }
3823    }
3824    
3825    void MainWindow::show_samples_tab() {
3826        m_TreeViewNotebook.set_current_page(0);
3827    }
3828    
3829    void MainWindow::show_intruments_tab() {
3830        m_TreeViewNotebook.set_current_page(1);
3831    }
3832    
3833    void MainWindow::show_scripts_tab() {
3834        m_TreeViewNotebook.set_current_page(2);
3835    }
3836    
3837    void MainWindow::select_prev_region() {
3838        m_RegionChooser.select_prev_region();
3839    }
3840    
3841    void MainWindow::select_next_region() {
3842        m_RegionChooser.select_next_region();
3843    }
3844    
3845    void MainWindow::select_next_dim_rgn_zone() {
3846        if (m_DimRegionChooser.has_focus()) return; // avoid conflict with key stroke handler of DimenionRegionChooser
3847        m_DimRegionChooser.select_next_dimzone();
3848    }
3849    
3850    void MainWindow::select_prev_dim_rgn_zone() {
3851        if (m_DimRegionChooser.has_focus()) return; // avoid conflict with key stroke handler of DimenionRegionChooser
3852        m_DimRegionChooser.select_prev_dimzone();
3853    }
3854    
3855    void MainWindow::select_add_next_dim_rgn_zone() {
3856        m_DimRegionChooser.select_next_dimzone(true);
3857    }
3858    
3859    void MainWindow::select_add_prev_dim_rgn_zone() {
3860        m_DimRegionChooser.select_prev_dimzone(true);
3861    }
3862    
3863    void MainWindow::select_prev_dimension() {
3864        if (m_DimRegionChooser.has_focus()) return; // avoid conflict with key stroke handler of DimenionRegionChooser
3865        m_DimRegionChooser.select_prev_dimension();
3866    }
3867    
3868    void MainWindow::select_next_dimension() {
3869        if (m_DimRegionChooser.has_focus()) return; // avoid conflict with key stroke handler of DimenionRegionChooser
3870        m_DimRegionChooser.select_next_dimension();
3871    }
3872    
3873    #define CLIPBOARD_DIMENSIONREGION_TARGET \
3874        ("libgig.DimensionRegion." + m_serializationArchive.rawDataFormat())
3875    
3876    void MainWindow::copy_selected_dimrgn() {
3877        gig::DimensionRegion* pDimRgn = m_DimRegionChooser.get_main_dimregion();
3878        if (!pDimRgn) {
3879            updateClipboardPasteAvailable();
3880            updateClipboardCopyAvailable();
3881            return;
3882        }
3883    
3884        std::vector<Gtk::TargetEntry> targets;
3885        targets.push_back( Gtk::TargetEntry(CLIPBOARD_DIMENSIONREGION_TARGET) );
3886    
3887        Glib::RefPtr<Gtk::Clipboard> clipboard = Gtk::Clipboard::get();
3888        clipboard->set(
3889            targets,
3890            sigc::mem_fun(*this, &MainWindow::on_clipboard_get),
3891            sigc::mem_fun(*this, &MainWindow::on_clipboard_clear)
3892        );
3893    
3894        m_serializationArchive.serialize(pDimRgn);
3895    
3896        updateClipboardPasteAvailable();
3897    }
3898    
3899    void MainWindow::paste_copied_dimrgn() {
3900        Glib::RefPtr<Gtk::Clipboard> clipboard = Gtk::Clipboard::get();
3901        clipboard->request_contents(
3902            CLIPBOARD_DIMENSIONREGION_TARGET,
3903            sigc::mem_fun(*this, &MainWindow::on_clipboard_received)
3904        );
3905        updateClipboardPasteAvailable();
3906    }
3907    
3908    void MainWindow::adjust_clipboard_content() {
3909        MacroEditor* editor = new MacroEditor();
3910        editor->setMacro(&m_serializationArchive, true);
3911        editor->show();
3912    }
3913    
3914    void MainWindow::updateClipboardPasteAvailable() {
3915        Glib::RefPtr<Gtk::Clipboard> clipboard = Gtk::Clipboard::get();
3916        clipboard->request_targets(
3917            sigc::mem_fun(*this, &MainWindow::on_clipboard_received_targets)
3918        );
3919    }
3920    
3921    void MainWindow::updateClipboardCopyAvailable() {
3922        bool bDimensionRegionCopyIsPossible = m_DimRegionChooser.get_main_dimregion();
3923        static_cast<Gtk::MenuItem*>(
3924            uiManager->get_widget("/MenuBar/MenuEdit/CopyDimRgn")
3925        )->set_sensitive(bDimensionRegionCopyIsPossible);
3926    }
3927    
3928    void MainWindow::on_clipboard_owner_change(GdkEventOwnerChange* event) {
3929        updateClipboardPasteAvailable();
3930    }
3931    
3932    void MainWindow::on_clipboard_get(Gtk::SelectionData& selection_data, guint /*info*/) {
3933        const std::string target = selection_data.get_target();
3934        if (target == CLIPBOARD_DIMENSIONREGION_TARGET) {
3935            selection_data.set(
3936                CLIPBOARD_DIMENSIONREGION_TARGET, 8 /* "format": probably unused*/,
3937                &m_serializationArchive.rawData()[0],
3938                m_serializationArchive.rawData().size()
3939            );
3940        } else {
3941            std::cerr << "Clipboard: content for unknown target '" << target << "' requested\n";
3942        }
3943    }
3944    
3945    void MainWindow::on_clipboard_clear() {
3946        m_serializationArchive.clear();
3947        updateClipboardPasteAvailable();
3948        updateClipboardCopyAvailable();
3949    }
3950    
3951    //NOTE: Might throw exception !!!
3952    void MainWindow::applyMacro(Serialization::Archive& macro) {
3953        gig::DimensionRegion* pDimRgn = m_DimRegionChooser.get_main_dimregion();
3954        if (!pDimRgn) return;
3955    
3956        for (std::set<gig::DimensionRegion*>::iterator itDimReg = dimreg_edit.dimregs.begin();
3957             itDimReg != dimreg_edit.dimregs.end(); ++itDimReg)
3958        {
3959            gig::DimensionRegion* pDimRgn = *itDimReg;
3960            DimRegionChangeGuard(this, pDimRgn);
3961            macro.deserialize(pDimRgn);
3962        }
3963        //region_changed()
3964        file_changed();
3965        dimreg_changed();
3966    }
3967    
3968    void MainWindow::on_clipboard_received(const Gtk::SelectionData& selection_data) {
3969        const std::string target = selection_data.get_target();
3970        if (target == CLIPBOARD_DIMENSIONREGION_TARGET) {
3971            Glib::ustring errorText;
3972            try {
3973                m_serializationArchive.decode(
3974                    selection_data.get_data(), selection_data.get_length()
3975                );
3976                applyMacro(m_serializationArchive);
3977            } catch (Serialization::Exception e) {
3978                errorText = e.Message;
3979            } catch (...) {
3980                errorText = _("Unknown exception while pasting DimensionRegion");
3981            }
3982            if (!errorText.empty()) {
3983                Glib::ustring txt = _("Pasting DimensionRegion failed:\n") + errorText;
3984                Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
3985                msg.run();
3986            }
3987        }
3988    }
3989    
3990    void MainWindow::on_clipboard_received_targets(const std::vector<Glib::ustring>& targets) {
3991        const bool bDimensionRegionPasteIsPossible =
3992            std::find(targets.begin(), targets.end(),
3993                      CLIPBOARD_DIMENSIONREGION_TARGET) != targets.end();
3994    
3995        static_cast<Gtk::MenuItem*>(
3996            uiManager->get_widget("/MenuBar/MenuEdit/PasteDimRgn")
3997        )->set_sensitive(bDimensionRegionPasteIsPossible);
3998    
3999        static_cast<Gtk::MenuItem*>(
4000            uiManager->get_widget("/MenuBar/MenuEdit/AdjustClipboard")
4001        )->set_sensitive(bDimensionRegionPasteIsPossible);
4002  }  }
4003    
4004  sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {  sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {
# Line 1885  sigc::signal<void, int/*key*/, int/*velo Line 4056  sigc::signal<void, int/*key*/, int/*velo
4056  sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_keyboard_key_released() {  sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_keyboard_key_released() {
4057      return m_RegionChooser.signal_keyboard_key_released();      return m_RegionChooser.signal_keyboard_key_released();
4058  }  }
4059    
4060    sigc::signal<void, gig::Instrument*>& MainWindow::signal_switch_sampler_instrument() {
4061        return switch_sampler_instrument_signal;
4062    }

Legend:
Removed from v.2151  
changed lines
  Added in v.3225

  ViewVC Help
Powered by ViewVC