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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3109 - (hide annotations) (download)
Sun Feb 12 16:35:03 2017 UTC (7 years, 1 month ago) by schoenebeck
File size: 140022 byte(s)
- Just added a "Legend:" label to the new symbols.

1 schoenebeck 1225 /*
2 schoenebeck 3089 * Copyright (C) 2006-2017 Andreas Persson
3 schoenebeck 1225 *
4     * This program is free software; you can redistribute it and/or
5     * modify it under the terms of the GNU General Public License as
6     * published by the Free Software Foundation; either version 2, or (at
7     * your option) any later version.
8     *
9     * This program is distributed in the hope that it will be useful, but
10     * WITHOUT ANY WARRANTY; without even the implied warranty of
11     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12     * General Public License for more details.
13     *
14     * You should have received a copy of the GNU General Public License
15     * along with program; see the file COPYING. If not, write to the Free
16     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17     * 02110-1301 USA.
18     */
19    
20     #include <iostream>
21 persson 1714 #include <cstring>
22 schoenebeck 1225
23 persson 2841 #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 persson 2325 #include <glibmm/convert.h>
32     #include <glibmm/dispatcher.h>
33     #include <glibmm/miscutils.h>
34     #include <glibmm/stringutils.h>
35 persson 2151 #include <gtkmm/aboutdialog.h>
36 schoenebeck 1225 #include <gtkmm/filechooserdialog.h>
37     #include <gtkmm/messagedialog.h>
38     #include <gtkmm/targetentry.h>
39     #include <gtkmm/main.h>
40 schoenebeck 1415 #include <gtkmm/toggleaction.h>
41 persson 2344 #if GTKMM_MAJOR_VERSION < 3
42 persson 1799 #include "wrapLabel.hh"
43 persson 2344 #endif
44 schoenebeck 1225
45 schoenebeck 1396 #include "global.h"
46 persson 2169 #include "compat.h"
47 schoenebeck 1396
48 schoenebeck 1225 #include <stdio.h>
49     #include <sndfile.h>
50 schoenebeck 2553 #include <assert.h>
51 schoenebeck 1225
52     #include "mainwindow.h"
53 schoenebeck 2541 #include "Settings.h"
54 schoenebeck 2548 #include "CombineInstrumentsDialog.h"
55 schoenebeck 2604 #include "scripteditor.h"
56 schoenebeck 2610 #include "scriptslots.h"
57 schoenebeck 2624 #include "ReferencesView.h"
58 schoenebeck 1411 #include "../../gfx/status_attached.xpm"
59     #include "../../gfx/status_detached.xpm"
60 schoenebeck 3106 #include "gfx/builtinpix.h"
61 schoenebeck 1411
62 persson 1533 MainWindow::MainWindow() :
63 schoenebeck 2626 m_DimRegionChooser(*this),
64 persson 1533 dimreg_label(_("Changes apply to:")),
65     dimreg_all_regions(_("all regions")),
66     dimreg_all_dimregs(_("all dimension splits")),
67 schoenebeck 3106 dimreg_stereo(_("both channels")),
68 schoenebeck 3109 labelLegend(_("Legend:")),
69 schoenebeck 3106 labelNoSample(_(" No Sample")),
70     labelMissingSample(_(" Missing some Sample(s)")),
71     labelLooped(_(" Looped")),
72     labelSomeLoops(_(" Some Loop(s)"))
73 schoenebeck 1225 {
74 schoenebeck 3106 loadBuiltInPix();
75    
76 schoenebeck 1225 // set_border_width(5);
77     // set_default_size(400, 200);
78    
79     add(m_VBox);
80    
81     // Handle selection
82 persson 2442 m_TreeView.get_selection()->signal_changed().connect(
83 schoenebeck 1225 sigc::mem_fun(*this, &MainWindow::on_sel_change));
84    
85     // m_TreeView.set_reorderable();
86    
87     m_TreeView.signal_button_press_event().connect_notify(
88     sigc::mem_fun(*this, &MainWindow::on_button_release));
89    
90     // Add the TreeView tab, inside a ScrolledWindow, with the button underneath:
91     m_ScrolledWindow.add(m_TreeView);
92     // m_ScrolledWindow.set_size_request(200, 600);
93     m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
94    
95     m_ScrolledWindowSamples.add(m_TreeViewSamples);
96     m_ScrolledWindowSamples.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
97    
98 schoenebeck 2604 m_ScrolledWindowScripts.add(m_TreeViewScripts);
99     m_ScrolledWindowScripts.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
100 schoenebeck 1225
101 schoenebeck 2604
102 schoenebeck 1225 m_TreeViewNotebook.set_size_request(300);
103    
104     m_HPaned.add1(m_TreeViewNotebook);
105 persson 1533 dimreg_hbox.add(dimreg_label);
106     dimreg_hbox.add(dimreg_all_regions);
107     dimreg_hbox.add(dimreg_all_dimregs);
108     dimreg_stereo.set_active();
109     dimreg_hbox.add(dimreg_stereo);
110     dimreg_vbox.add(dimreg_edit);
111 persson 1582 dimreg_vbox.pack_start(dimreg_hbox, Gtk::PACK_SHRINK);
112 schoenebeck 3106 {
113 schoenebeck 3109 legend_hbox.add(labelLegend);
114    
115 schoenebeck 3106 imageNoSample.set(redDot);
116 schoenebeck 3108 imageNoSample.set_alignment(Gtk::ALIGN_END);
117     labelNoSample.set_alignment(Gtk::ALIGN_START);
118 schoenebeck 3106 legend_hbox.add(imageNoSample);
119     legend_hbox.add(labelNoSample);
120    
121     imageMissingSample.set(yellowDot);
122 schoenebeck 3108 imageMissingSample.set_alignment(Gtk::ALIGN_END);
123     labelMissingSample.set_alignment(Gtk::ALIGN_START);
124 schoenebeck 3106 legend_hbox.add(imageMissingSample);
125     legend_hbox.add(labelMissingSample);
126    
127     imageLooped.set(blackLoop);
128 schoenebeck 3108 imageLooped.set_alignment(Gtk::ALIGN_END);
129     labelLooped.set_alignment(Gtk::ALIGN_START);
130 schoenebeck 3106 legend_hbox.add(imageLooped);
131     legend_hbox.add(labelLooped);
132    
133     imageSomeLoops.set(grayLoop);
134 schoenebeck 3108 imageSomeLoops.set_alignment(Gtk::ALIGN_END);
135     labelSomeLoops.set_alignment(Gtk::ALIGN_START);
136 schoenebeck 3106 legend_hbox.add(imageSomeLoops);
137     legend_hbox.add(labelSomeLoops);
138    
139     legend_hbox.show_all_children();
140     }
141     dimreg_vbox.pack_start(legend_hbox, Gtk::PACK_SHRINK);
142 persson 1533 m_HPaned.add2(dimreg_vbox);
143 schoenebeck 1225
144 schoenebeck 2536 dimreg_label.set_tooltip_text(_("To automatically apply your changes above globally to the entire instrument, check all 3 check boxes on the right."));
145     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."));
146     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."));
147     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)."));
148 schoenebeck 1225
149 persson 1831 m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, _("Samples"));
150     m_TreeViewNotebook.append_page(m_ScrolledWindow, _("Instruments"));
151 schoenebeck 2604 m_TreeViewNotebook.append_page(m_ScrolledWindowScripts, _("Scripts"));
152 schoenebeck 1225
153     actionGroup = Gtk::ActionGroup::create();
154    
155     actionGroup->add(Gtk::Action::create("MenuFile", _("_File")));
156 persson 2845 actionGroup->add(Gtk::Action::create("New", _("_New")),
157     Gtk::AccelKey("<control>n"),
158 schoenebeck 1225 sigc::mem_fun(
159     *this, &MainWindow::on_action_file_new));
160 persson 2845 actionGroup->add(Gtk::Action::create("Open", _("_Open...")),
161     Gtk::AccelKey("<control>o"),
162 schoenebeck 1225 sigc::mem_fun(
163     *this, &MainWindow::on_action_file_open));
164 persson 2845 actionGroup->add(Gtk::Action::create("Save", _("_Save")),
165     Gtk::AccelKey("<control>s"),
166 schoenebeck 1225 sigc::mem_fun(
167     *this, &MainWindow::on_action_file_save));
168 persson 2845 actionGroup->add(Gtk::Action::create("SaveAs", _("Save _As...")),
169 persson 1261 Gtk::AccelKey("<shift><control>s"),
170 schoenebeck 1225 sigc::mem_fun(
171 persson 1261 *this, &MainWindow::on_action_file_save_as));
172 schoenebeck 1225 actionGroup->add(Gtk::Action::create("Properties",
173 persson 2845 _("_Properties")),
174 schoenebeck 1225 sigc::mem_fun(
175     *this, &MainWindow::on_action_file_properties));
176     actionGroup->add(Gtk::Action::create("InstrProperties",
177 persson 2845 _("_Properties")),
178 schoenebeck 1225 sigc::mem_fun(
179     *this, &MainWindow::show_instr_props));
180 persson 2507 actionGroup->add(Gtk::Action::create("MidiRules",
181 schoenebeck 2610 _("_Midi Rules...")),
182 persson 2507 sigc::mem_fun(
183     *this, &MainWindow::show_midi_rules));
184 schoenebeck 2610 actionGroup->add(Gtk::Action::create("ScriptSlots",
185     _("_Script Slots...")),
186     sigc::mem_fun(
187     *this, &MainWindow::show_script_slots));
188 persson 2845 actionGroup->add(Gtk::Action::create("Quit", _("_Quit")),
189     Gtk::AccelKey("<control>q"),
190 schoenebeck 1225 sigc::mem_fun(
191 persson 1261 *this, &MainWindow::on_action_quit));
192 schoenebeck 2625 actionGroup->add(
193     Gtk::Action::create("MenuSample", _("_Sample")),
194     sigc::mem_fun(*this, &MainWindow::show_samples_tab)
195     );
196     actionGroup->add(
197     Gtk::Action::create("MenuInstrument", _("_Instrument")),
198     sigc::mem_fun(*this, &MainWindow::show_intruments_tab)
199     );
200     actionGroup->add(
201     Gtk::Action::create("MenuScript", _("S_cript")),
202     sigc::mem_fun(*this, &MainWindow::show_scripts_tab)
203     );
204     actionGroup->add(Gtk::Action::create("AllInstruments", _("_Select")));
205 schoenebeck 1225
206 schoenebeck 2464 actionGroup->add(Gtk::Action::create("MenuEdit", _("_Edit")));
207    
208     Glib::RefPtr<Gtk::ToggleAction> toggle_action =
209 schoenebeck 2536 Gtk::ToggleAction::create("CopySampleUnity", _("Copy Sample's _Unity Note"));
210 schoenebeck 2464 toggle_action->set_active(true);
211     actionGroup->add(toggle_action);
212    
213     toggle_action =
214     Gtk::ToggleAction::create("CopySampleTune", _("Copy Sample's _Fine Tune"));
215     toggle_action->set_active(true);
216     actionGroup->add(toggle_action);
217    
218     toggle_action =
219     Gtk::ToggleAction::create("CopySampleLoop", _("Copy Sample's _Loop Points"));
220     toggle_action->set_active(true);
221     actionGroup->add(toggle_action);
222    
223    
224 schoenebeck 1415 actionGroup->add(Gtk::Action::create("MenuView", _("_View")));
225 schoenebeck 2464 toggle_action =
226 schoenebeck 1415 Gtk::ToggleAction::create("Statusbar", _("_Statusbar"));
227     toggle_action->set_active(true);
228     actionGroup->add(toggle_action,
229     sigc::mem_fun(
230     *this, &MainWindow::on_action_view_status_bar));
231 schoenebeck 2918
232     toggle_action =
233     Gtk::ToggleAction::create("AutoRestoreWinDim", _("_Auto Restore Window Dimension"));
234     toggle_action->set_active(Settings::singleton()->autoRestoreWindowDimension);
235     actionGroup->add(toggle_action,
236     sigc::mem_fun(
237     *this, &MainWindow::on_auto_restore_win_dim));
238    
239 schoenebeck 2967 toggle_action =
240     Gtk::ToggleAction::create("SaveWithTemporaryFile", _("Save with _temporary file"));
241     toggle_action->set_active(Settings::singleton()->saveWithTemporaryFile);
242     actionGroup->add(toggle_action,
243     sigc::mem_fun(
244     *this, &MainWindow::on_save_with_temporary_file));
245    
246 schoenebeck 2772 actionGroup->add(
247     Gtk::Action::create("RefreshAll", _("_Refresh All")),
248     sigc::mem_fun(*this, &MainWindow::on_action_refresh_all)
249     );
250 schoenebeck 1415
251 persson 2845 actionGroup->add(Gtk::Action::create("MenuHelp", _("_Help")));
252     actionGroup->add(Gtk::Action::create("About", _("_About")),
253 schoenebeck 1225 sigc::mem_fun(
254     *this, &MainWindow::on_action_help_about));
255     actionGroup->add(
256     Gtk::Action::create("AddInstrument", _("Add _Instrument")),
257     sigc::mem_fun(*this, &MainWindow::on_action_add_instrument)
258     );
259     actionGroup->add(
260 schoenebeck 2395 Gtk::Action::create("DupInstrument", _("_Duplicate Instrument")),
261     sigc::mem_fun(*this, &MainWindow::on_action_duplicate_instrument)
262     );
263     actionGroup->add(
264 persson 2845 Gtk::Action::create("RemoveInstrument", _("_Remove")),
265 schoenebeck 1225 sigc::mem_fun(*this, &MainWindow::on_action_remove_instrument)
266     );
267    
268 schoenebeck 2541
269     actionGroup->add(Gtk::Action::create("MenuSettings", _("_Settings")));
270    
271     toggle_action =
272     Gtk::ToggleAction::create("WarnUserOnExtensions", _("Show warning on format _extensions"));
273     toggle_action->set_active(Settings::singleton()->warnUserOnExtensions);
274     actionGroup->add(
275     toggle_action,
276     sigc::mem_fun(*this, &MainWindow::on_action_warn_user_on_extensions)
277     );
278    
279 schoenebeck 2689 toggle_action =
280     Gtk::ToggleAction::create("SyncSamplerInstrumentSelection", _("Synchronize sampler's instrument selection"));
281     toggle_action->set_active(Settings::singleton()->syncSamplerInstrumentSelection);
282     actionGroup->add(
283     toggle_action,
284     sigc::mem_fun(*this, &MainWindow::on_action_sync_sampler_instrument_selection)
285     );
286 schoenebeck 2541
287 schoenebeck 2773 toggle_action =
288     Gtk::ToggleAction::create("MoveRootNoteWithRegionMoved", _("Move root note with region moved"));
289     toggle_action->set_active(Settings::singleton()->moveRootNoteWithRegionMoved);
290     actionGroup->add(
291     toggle_action,
292     sigc::mem_fun(*this, &MainWindow::on_action_move_root_note_with_region_moved)
293     );
294 schoenebeck 2689
295 schoenebeck 2773
296 schoenebeck 2548 actionGroup->add(Gtk::Action::create("MenuTools", _("_Tools")));
297    
298     actionGroup->add(
299     Gtk::Action::create("CombineInstruments", _("_Combine Instruments...")),
300     sigc::mem_fun(*this, &MainWindow::on_action_combine_instruments)
301     );
302    
303 schoenebeck 2553 actionGroup->add(
304     Gtk::Action::create("MergeFiles", _("_Merge Files...")),
305     sigc::mem_fun(*this, &MainWindow::on_action_merge_files)
306     );
307 schoenebeck 2548
308 schoenebeck 2553
309 schoenebeck 1225 // sample right-click popup actions
310     actionGroup->add(
311 persson 2845 Gtk::Action::create("SampleProperties", _("_Properties")),
312 schoenebeck 1225 sigc::mem_fun(*this, &MainWindow::on_action_sample_properties)
313     );
314     actionGroup->add(
315     Gtk::Action::create("AddGroup", _("Add _Group")),
316     sigc::mem_fun(*this, &MainWindow::on_action_add_group)
317     );
318     actionGroup->add(
319 persson 1799 Gtk::Action::create("AddSample", _("Add _Sample(s)...")),
320 schoenebeck 1225 sigc::mem_fun(*this, &MainWindow::on_action_add_sample)
321     );
322     actionGroup->add(
323 persson 2845 Gtk::Action::create("RemoveSample", _("_Remove")),
324 schoenebeck 1225 sigc::mem_fun(*this, &MainWindow::on_action_remove_sample)
325     );
326 schoenebeck 1673 actionGroup->add(
327 schoenebeck 2772 Gtk::Action::create("RemoveUnusedSamples", _("Remove _Unused Samples")),
328     sigc::mem_fun(*this, &MainWindow::on_action_remove_unused_samples)
329     );
330     actionGroup->add(
331 schoenebeck 2624 Gtk::Action::create("ShowSampleRefs", _("Show References...")),
332     sigc::mem_fun(*this, &MainWindow::on_action_view_references)
333     );
334     actionGroup->add(
335 schoenebeck 2715 Gtk::Action::create("ReplaceSample",
336     _("Replace Sample...")),
337     sigc::mem_fun(*this, &MainWindow::on_action_replace_sample)
338     );
339     actionGroup->add(
340 persson 1799 Gtk::Action::create("ReplaceAllSamplesInAllGroups",
341     _("Replace All Samples in All Groups...")),
342 schoenebeck 1673 sigc::mem_fun(*this, &MainWindow::on_action_replace_all_samples_in_all_groups)
343     );
344 schoenebeck 2604
345     // script right-click popup actions
346     actionGroup->add(
347     Gtk::Action::create("AddScriptGroup", _("Add _Group")),
348     sigc::mem_fun(*this, &MainWindow::on_action_add_script_group)
349     );
350     actionGroup->add(
351     Gtk::Action::create("AddScript", _("Add _Script")),
352     sigc::mem_fun(*this, &MainWindow::on_action_add_script)
353     );
354     actionGroup->add(
355     Gtk::Action::create("EditScript", _("_Edit Script...")),
356     sigc::mem_fun(*this, &MainWindow::on_action_edit_script)
357     );
358     actionGroup->add(
359 persson 2845 Gtk::Action::create("RemoveScript", _("_Remove")),
360 schoenebeck 2604 sigc::mem_fun(*this, &MainWindow::on_action_remove_script)
361     );
362 schoenebeck 1225
363     uiManager = Gtk::UIManager::create();
364     uiManager->insert_action_group(actionGroup);
365 persson 1261 add_accel_group(uiManager->get_accel_group());
366 schoenebeck 1225
367     Glib::ustring ui_info =
368     "<ui>"
369     " <menubar name='MenuBar'>"
370     " <menu action='MenuFile'>"
371     " <menuitem action='New'/>"
372     " <menuitem action='Open'/>"
373     " <separator/>"
374     " <menuitem action='Save'/>"
375     " <menuitem action='SaveAs'/>"
376     " <separator/>"
377     " <menuitem action='Properties'/>"
378     " <separator/>"
379     " <menuitem action='Quit'/>"
380     " </menu>"
381 schoenebeck 2464 " <menu action='MenuEdit'>"
382     " <menuitem action='CopySampleUnity'/>"
383     " <menuitem action='CopySampleTune'/>"
384     " <menuitem action='CopySampleLoop'/>"
385     " </menu>"
386 schoenebeck 2625 " <menu action='MenuSample'>"
387     " <menuitem action='SampleProperties'/>"
388     " <menuitem action='AddGroup'/>"
389     " <menuitem action='AddSample'/>"
390     " <menuitem action='ShowSampleRefs'/>"
391 schoenebeck 2715 " <menuitem action='ReplaceSample' />"
392 schoenebeck 2625 " <menuitem action='ReplaceAllSamplesInAllGroups' />"
393     " <separator/>"
394     " <menuitem action='RemoveSample'/>"
395 schoenebeck 2772 " <menuitem action='RemoveUnusedSamples'/>"
396 schoenebeck 2625 " </menu>"
397 schoenebeck 1225 " <menu action='MenuInstrument'>"
398 schoenebeck 2625 " <menu action='AllInstruments'>"
399     " </menu>"
400     " <separator/>"
401     " <menuitem action='InstrProperties'/>"
402     " <menuitem action='MidiRules'/>"
403     " <menuitem action='ScriptSlots'/>"
404     " <menuitem action='AddInstrument'/>"
405     " <menuitem action='DupInstrument'/>"
406     " <separator/>"
407     " <menuitem action='RemoveInstrument'/>"
408 schoenebeck 1225 " </menu>"
409 schoenebeck 2625 " <menu action='MenuScript'>"
410     " <menuitem action='AddScriptGroup'/>"
411     " <menuitem action='AddScript'/>"
412     " <menuitem action='EditScript'/>"
413     " <separator/>"
414     " <menuitem action='RemoveScript'/>"
415     " </menu>"
416 schoenebeck 1415 " <menu action='MenuView'>"
417     " <menuitem action='Statusbar'/>"
418 schoenebeck 2918 " <menuitem action='AutoRestoreWinDim'/>"
419 schoenebeck 2772 " <separator/>"
420     " <menuitem action='RefreshAll'/>"
421 schoenebeck 1415 " </menu>"
422 schoenebeck 2548 " <menu action='MenuTools'>"
423     " <menuitem action='CombineInstruments'/>"
424 schoenebeck 2553 " <menuitem action='MergeFiles'/>"
425 schoenebeck 2548 " </menu>"
426 schoenebeck 2541 " <menu action='MenuSettings'>"
427     " <menuitem action='WarnUserOnExtensions'/>"
428 schoenebeck 2689 " <menuitem action='SyncSamplerInstrumentSelection'/>"
429 schoenebeck 2773 " <menuitem action='MoveRootNoteWithRegionMoved'/>"
430 schoenebeck 2967 " <menuitem action='SaveWithTemporaryFile'/>"
431 schoenebeck 2541 " </menu>"
432 schoenebeck 1225 " <menu action='MenuHelp'>"
433     " <menuitem action='About'/>"
434     " </menu>"
435     " </menubar>"
436     " <popup name='PopupMenu'>"
437     " <menuitem action='InstrProperties'/>"
438 persson 2507 " <menuitem action='MidiRules'/>"
439 schoenebeck 2610 " <menuitem action='ScriptSlots'/>"
440 schoenebeck 1225 " <menuitem action='AddInstrument'/>"
441 schoenebeck 2395 " <menuitem action='DupInstrument'/>"
442 schoenebeck 1225 " <separator/>"
443     " <menuitem action='RemoveInstrument'/>"
444     " </popup>"
445     " <popup name='SamplePopupMenu'>"
446     " <menuitem action='SampleProperties'/>"
447     " <menuitem action='AddGroup'/>"
448     " <menuitem action='AddSample'/>"
449 schoenebeck 2624 " <menuitem action='ShowSampleRefs'/>"
450 schoenebeck 2715 " <menuitem action='ReplaceSample' />"
451 persson 2442 " <menuitem action='ReplaceAllSamplesInAllGroups' />"
452 schoenebeck 1225 " <separator/>"
453     " <menuitem action='RemoveSample'/>"
454 schoenebeck 2772 " <menuitem action='RemoveUnusedSamples'/>"
455 schoenebeck 1225 " </popup>"
456 schoenebeck 2604 " <popup name='ScriptPopupMenu'>"
457     " <menuitem action='AddScriptGroup'/>"
458     " <menuitem action='AddScript'/>"
459     " <menuitem action='EditScript'/>"
460     " <separator/>"
461     " <menuitem action='RemoveScript'/>"
462     " </popup>"
463 schoenebeck 1225 "</ui>";
464     uiManager->add_ui_from_string(ui_info);
465    
466     popup_menu = dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/PopupMenu"));
467 schoenebeck 2536
468     // Set tooltips for menu items (for some reason, setting a tooltip on the
469     // respective Gtk::Action objects above will simply be ignored, no matter
470     // if using Gtk::Action::set_tooltip() or passing the tooltip string on
471     // Gtk::Action::create()).
472     {
473     Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
474     uiManager->get_widget("/MenuBar/MenuEdit/CopySampleUnity"));
475     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."));
476     }
477     {
478     Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
479     uiManager->get_widget("/MenuBar/MenuEdit/CopySampleTune"));
480     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."));
481     }
482     {
483     Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
484     uiManager->get_widget("/MenuBar/MenuEdit/CopySampleLoop"));
485     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."));
486     }
487 schoenebeck 2541 {
488     Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
489     uiManager->get_widget("/MenuBar/MenuSettings/WarnUserOnExtensions"));
490     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."));
491     }
492 schoenebeck 2553 {
493     Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
494 schoenebeck 2689 uiManager->get_widget("/MenuBar/MenuSettings/SyncSamplerInstrumentSelection"));
495     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)."));
496     }
497     {
498     Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
499 schoenebeck 2773 uiManager->get_widget("/MenuBar/MenuSettings/MoveRootNoteWithRegionMoved"));
500     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."));
501     }
502     {
503     Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
504 schoenebeck 2772 uiManager->get_widget("/MenuBar/MenuSample/RemoveUnusedSamples"));
505     item->set_tooltip_text(_("Removes all samples that are not referenced by any instrument (i.e. red ones)."));
506     // copy tooltip to popup menu
507     Gtk::MenuItem* item2 = dynamic_cast<Gtk::MenuItem*>(
508     uiManager->get_widget("/SamplePopupMenu/RemoveUnusedSamples"));
509     item2->set_tooltip_text(item->get_tooltip_text());
510     }
511     {
512     Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
513     uiManager->get_widget("/MenuBar/MenuView/RefreshAll"));
514     item->set_tooltip_text(_("Reloads the currently open gig file and updates the entire graphical user interface."));
515     }
516     {
517     Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
518 schoenebeck 2918 uiManager->get_widget("/MenuBar/MenuView/AutoRestoreWinDim"));
519     item->set_tooltip_text(_("If checked, size and position of all windows will be saved and automatically restored next time."));
520     }
521     {
522     Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
523 schoenebeck 2553 uiManager->get_widget("/MenuBar/MenuTools/CombineInstruments"));
524     item->set_tooltip_text(_("Create combi sounds out of individual sounds of this .gig file."));
525     }
526     {
527     Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
528     uiManager->get_widget("/MenuBar/MenuTools/MergeFiles"));
529     item->set_tooltip_text(_("Add instruments and samples of other .gig files to this .gig file."));
530     }
531 schoenebeck 1225
532 schoenebeck 2553
533 persson 2442 instrument_menu = static_cast<Gtk::MenuItem*>(
534 schoenebeck 2625 uiManager->get_widget("/MenuBar/MenuInstrument/AllInstruments"))->get_submenu();
535 persson 2442
536 schoenebeck 1225 Gtk::Widget* menuBar = uiManager->get_widget("/MenuBar");
537     m_VBox.pack_start(*menuBar, Gtk::PACK_SHRINK);
538     m_VBox.pack_start(m_HPaned);
539     m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
540 schoenebeck 1661 m_VBox.pack_start(m_RegionChooser.m_VirtKeybPropsBox, Gtk::PACK_SHRINK);
541 schoenebeck 1225 m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
542 schoenebeck 1411 m_VBox.pack_start(m_StatusBar, Gtk::PACK_SHRINK);
543 schoenebeck 1225
544 persson 2246 set_file_is_shared(false);
545    
546 schoenebeck 1411 // Status Bar:
547     m_StatusBar.pack_start(m_AttachedStateLabel, Gtk::PACK_SHRINK);
548     m_StatusBar.pack_start(m_AttachedStateImage, Gtk::PACK_SHRINK);
549     m_StatusBar.show();
550    
551 persson 1261 m_RegionChooser.signal_region_selected().connect(
552 schoenebeck 1225 sigc::mem_fun(*this, &MainWindow::region_changed) );
553 persson 1261 m_DimRegionChooser.signal_dimregion_selected().connect(
554 schoenebeck 1225 sigc::mem_fun(*this, &MainWindow::dimreg_changed) );
555    
556    
557     // Create the Tree model:
558     m_refTreeModel = Gtk::ListStore::create(m_Columns);
559     m_TreeView.set_model(m_refTreeModel);
560 schoenebeck 2994 m_TreeView.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
561 schoenebeck 2701 m_TreeView.set_tooltip_text(_("Right click here for actions on instruments & MIDI Rules. Drag & drop to change the order of instruments."));
562 persson 2442 instrument_name_connection = m_refTreeModel->signal_row_changed().connect(
563 schoenebeck 1225 sigc::mem_fun(*this, &MainWindow::instrument_name_changed)
564     );
565    
566     // Add the TreeView's view columns:
567 schoenebeck 2994 m_TreeView.append_column(_("Nr"), m_Columns.m_col_nr);
568     m_TreeView.append_column_editable(_("Instrument"), m_Columns.m_col_name);
569     m_TreeView.set_headers_visible(true);
570 schoenebeck 2701
571     // establish drag&drop within the instrument tree view, allowing to reorder
572     // the sequence of instruments within the gig file
573     {
574     std::vector<Gtk::TargetEntry> drag_target_instrument;
575     drag_target_instrument.push_back(Gtk::TargetEntry("gig::Instrument"));
576     m_TreeView.drag_source_set(drag_target_instrument);
577     m_TreeView.drag_dest_set(drag_target_instrument);
578     m_TreeView.signal_drag_begin().connect(
579     sigc::mem_fun(*this, &MainWindow::on_instruments_treeview_drag_begin)
580     );
581     m_TreeView.signal_drag_data_get().connect(
582     sigc::mem_fun(*this, &MainWindow::on_instruments_treeview_drag_data_get)
583     );
584     m_TreeView.signal_drag_data_received().connect(
585     sigc::mem_fun(*this, &MainWindow::on_instruments_treeview_drop_drag_data_received)
586     );
587     }
588 schoenebeck 1225
589     // create samples treeview (including its data model)
590     m_refSamplesTreeModel = SamplesTreeStore::create(m_SamplesModel);
591     m_TreeViewSamples.set_model(m_refSamplesTreeModel);
592 schoenebeck 2994 m_TreeViewSamples.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
593 schoenebeck 2536 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."));
594 schoenebeck 1225 // m_TreeViewSamples.set_reorderable();
595 schoenebeck 2621 m_TreeViewSamples.append_column_editable(_("Name"), m_SamplesModel.m_col_name);
596     m_TreeViewSamples.append_column(_("Referenced"), m_SamplesModel.m_col_refcount);
597     {
598     Gtk::TreeViewColumn* column = m_TreeViewSamples.get_column(0);
599     Gtk::CellRendererText* cellrenderer =
600 persson 2658 dynamic_cast<Gtk::CellRendererText*>(column->get_first_cell());
601 schoenebeck 2621 column->add_attribute(
602     cellrenderer->property_foreground(), m_SamplesModel.m_color
603     );
604     }
605     {
606     Gtk::TreeViewColumn* column = m_TreeViewSamples.get_column(1);
607     Gtk::CellRendererText* cellrenderer =
608 persson 2658 dynamic_cast<Gtk::CellRendererText*>(column->get_first_cell());
609 schoenebeck 2621 column->add_attribute(
610     cellrenderer->property_foreground(), m_SamplesModel.m_color
611     );
612     }
613     m_TreeViewSamples.set_headers_visible(true);
614 schoenebeck 1225 m_TreeViewSamples.signal_button_press_event().connect_notify(
615     sigc::mem_fun(*this, &MainWindow::on_sample_treeview_button_release)
616     );
617     m_refSamplesTreeModel->signal_row_changed().connect(
618     sigc::mem_fun(*this, &MainWindow::sample_name_changed)
619     );
620    
621 schoenebeck 2604 // create scripts treeview (including its data model)
622     m_refScriptsTreeModel = ScriptsTreeStore::create(m_ScriptsModel);
623     m_TreeViewScripts.set_model(m_refScriptsTreeModel);
624     m_TreeViewScripts.set_tooltip_text(_(
625 schoenebeck 2644 "Use CTRL + double click for editing a script."
626     "\n\n"
627 schoenebeck 2604 "Note: instrument scripts are a LinuxSampler extension of the gig "
628     "format. This feature will not work with the GigaStudio software!"
629     ));
630     // m_TreeViewScripts.set_reorderable();
631     m_TreeViewScripts.append_column_editable("Samples", m_ScriptsModel.m_col_name);
632     m_TreeViewScripts.set_headers_visible(false);
633     m_TreeViewScripts.signal_button_press_event().connect_notify(
634     sigc::mem_fun(*this, &MainWindow::on_script_treeview_button_release)
635     );
636 schoenebeck 2695 //FIXME: why the heck does this double click signal_row_activated() only fire while CTRL key is pressed ?
637 schoenebeck 2644 m_TreeViewScripts.signal_row_activated().connect(
638     sigc::mem_fun(*this, &MainWindow::script_double_clicked)
639     );
640 schoenebeck 2604 m_refScriptsTreeModel->signal_row_changed().connect(
641     sigc::mem_fun(*this, &MainWindow::script_name_changed)
642     );
643    
644 schoenebeck 2610 // establish drag&drop between scripts tree view and ScriptSlots window
645     std::vector<Gtk::TargetEntry> drag_target_gig_script;
646     drag_target_gig_script.push_back(Gtk::TargetEntry("gig::Script"));
647     m_TreeViewScripts.drag_source_set(drag_target_gig_script);
648     m_TreeViewScripts.signal_drag_begin().connect(
649     sigc::mem_fun(*this, &MainWindow::on_scripts_treeview_drag_begin)
650     );
651     m_TreeViewScripts.signal_drag_data_get().connect(
652     sigc::mem_fun(*this, &MainWindow::on_scripts_treeview_drag_data_get)
653     );
654    
655 schoenebeck 1225 // establish drag&drop between samples tree view and dimension region 'Sample' text entry
656 persson 2169 std::vector<Gtk::TargetEntry> drag_target_gig_sample;
657     drag_target_gig_sample.push_back(Gtk::TargetEntry("gig::Sample"));
658 schoenebeck 1225 m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
659 persson 1303 m_TreeViewSamples.signal_drag_begin().connect(
660     sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)
661     );
662 schoenebeck 1225 m_TreeViewSamples.signal_drag_data_get().connect(
663     sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
664     );
665     dimreg_edit.wSample->drag_dest_set(drag_target_gig_sample);
666     dimreg_edit.wSample->signal_drag_data_received().connect(
667     sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
668     );
669 persson 1261 dimreg_edit.signal_dimreg_changed().connect(
670 schoenebeck 1322 sigc::hide(sigc::mem_fun(*this, &MainWindow::file_changed)));
671 persson 1261 m_RegionChooser.signal_instrument_changed().connect(
672     sigc::mem_fun(*this, &MainWindow::file_changed));
673 schoenebeck 2773 m_RegionChooser.signal_instrument_changed().connect(
674     sigc::mem_fun(*this, &MainWindow::region_changed));
675 persson 1261 m_DimRegionChooser.signal_region_changed().connect(
676     sigc::mem_fun(*this, &MainWindow::file_changed));
677 persson 2423 instrumentProps.signal_changed().connect(
678 persson 1261 sigc::mem_fun(*this, &MainWindow::file_changed));
679 persson 2423 propDialog.signal_changed().connect(
680 persson 1582 sigc::mem_fun(*this, &MainWindow::file_changed));
681 persson 2507 midiRules.signal_changed().connect(
682     sigc::mem_fun(*this, &MainWindow::file_changed));
683 schoenebeck 1322
684     dimreg_edit.signal_dimreg_to_be_changed().connect(
685     dimreg_to_be_changed_signal.make_slot());
686     dimreg_edit.signal_dimreg_changed().connect(
687     dimreg_changed_signal.make_slot());
688     dimreg_edit.signal_sample_ref_changed().connect(
689     sample_ref_changed_signal.make_slot());
690 schoenebeck 2621 sample_ref_changed_signal.connect(
691     sigc::mem_fun(*this, &MainWindow::on_sample_ref_changed)
692     );
693     samples_to_be_removed_signal.connect(
694     sigc::mem_fun(*this, &MainWindow::on_samples_to_be_removed)
695     );
696 schoenebeck 1322
697 schoenebeck 2691 dimreg_edit.signal_select_sample().connect(
698     sigc::mem_fun(*this, &MainWindow::select_sample)
699     );
700    
701 schoenebeck 1322 m_RegionChooser.signal_instrument_struct_to_be_changed().connect(
702     sigc::hide(
703     sigc::bind(
704     file_structure_to_be_changed_signal.make_slot(),
705     sigc::ref(this->file)
706     )
707     )
708     );
709     m_RegionChooser.signal_instrument_struct_changed().connect(
710     sigc::hide(
711     sigc::bind(
712     file_structure_changed_signal.make_slot(),
713     sigc::ref(this->file)
714     )
715     )
716     );
717     m_RegionChooser.signal_region_to_be_changed().connect(
718     region_to_be_changed_signal.make_slot());
719     m_RegionChooser.signal_region_changed_signal().connect(
720     region_changed_signal.make_slot());
721    
722 schoenebeck 1654 note_on_signal.connect(
723     sigc::mem_fun(m_RegionChooser, &RegionChooser::on_note_on_event));
724     note_off_signal.connect(
725     sigc::mem_fun(m_RegionChooser, &RegionChooser::on_note_off_event));
726    
727 persson 1533 dimreg_all_regions.signal_toggled().connect(
728     sigc::mem_fun(*this, &MainWindow::update_dimregs));
729     dimreg_all_dimregs.signal_toggled().connect(
730     sigc::mem_fun(*this, &MainWindow::dimreg_all_dimregs_toggled));
731     dimreg_stereo.signal_toggled().connect(
732     sigc::mem_fun(*this, &MainWindow::update_dimregs));
733    
734 schoenebeck 1225 file = 0;
735 persson 1261 file_is_changed = false;
736 schoenebeck 1225
737     show_all_children();
738 schoenebeck 1300
739     // start with a new gig file by default
740     on_action_file_new();
741 schoenebeck 2550
742     // select 'Instruments' tab by default
743     // (gtk allows this only if the tab childs are visible, thats why it's here)
744     m_TreeViewNotebook.set_current_page(1);
745 schoenebeck 1225 }
746    
747     MainWindow::~MainWindow()
748     {
749     }
750    
751 persson 1261 bool MainWindow::on_delete_event(GdkEventAny* event)
752     {
753 schoenebeck 1382 return !file_is_shared && file_is_changed && !close_confirmation_dialog();
754 persson 1261 }
755    
756     void MainWindow::on_action_quit()
757     {
758 schoenebeck 1382 if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
759 persson 1261 hide();
760     }
761    
762 schoenebeck 1225 void MainWindow::region_changed()
763     {
764     m_DimRegionChooser.set_region(m_RegionChooser.get_region());
765     }
766    
767 persson 1533 gig::Instrument* MainWindow::get_instrument()
768 schoenebeck 1225 {
769 persson 1533 gig::Instrument* instrument = 0;
770 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows = m_TreeView.get_selection()->get_selected_rows();
771     if (rows.empty()) return NULL;
772     Gtk::TreeModel::const_iterator it = m_refTreeModel->get_iter(rows[0]);
773 schoenebeck 1225 if (it) {
774     Gtk::TreeModel::Row row = *it;
775 persson 1533 instrument = row[m_Columns.m_col_instr];
776     }
777     return instrument;
778     }
779 schoenebeck 1225
780 persson 1533 void MainWindow::add_region_to_dimregs(gig::Region* region, bool stereo, bool all_dimregs)
781     {
782     if (all_dimregs) {
783     for (int i = 0 ; i < region->DimensionRegions ; i++) {
784     if (region->pDimensionRegions[i]) {
785     dimreg_edit.dimregs.insert(region->pDimensionRegions[i]);
786     }
787     }
788 schoenebeck 1225 } else {
789 persson 1533 m_DimRegionChooser.get_dimregions(region, stereo, dimreg_edit.dimregs);
790 schoenebeck 1225 }
791     }
792    
793 persson 1533 void MainWindow::update_dimregs()
794     {
795     dimreg_edit.dimregs.clear();
796     bool all_regions = dimreg_all_regions.get_active();
797     bool stereo = dimreg_stereo.get_active();
798     bool all_dimregs = dimreg_all_dimregs.get_active();
799    
800     if (all_regions) {
801     gig::Instrument* instrument = get_instrument();
802     if (instrument) {
803     for (gig::Region* region = instrument->GetFirstRegion() ;
804     region ;
805     region = instrument->GetNextRegion()) {
806     add_region_to_dimregs(region, stereo, all_dimregs);
807     }
808     }
809     } else {
810     gig::Region* region = m_RegionChooser.get_region();
811     if (region) {
812     add_region_to_dimregs(region, stereo, all_dimregs);
813     }
814     }
815 schoenebeck 3089
816     m_DimRegionChooser.setModifyAllRegions(all_regions);
817     m_DimRegionChooser.setModifyAllDimensionRegions(all_dimregs);
818     m_DimRegionChooser.setModifyBothChannels(stereo);
819 persson 1533 }
820    
821     void MainWindow::dimreg_all_dimregs_toggled()
822     {
823     dimreg_stereo.set_sensitive(!dimreg_all_dimregs.get_active());
824     update_dimregs();
825     }
826    
827     void MainWindow::dimreg_changed()
828     {
829     update_dimregs();
830 schoenebeck 2626 dimreg_edit.set_dim_region(m_DimRegionChooser.get_main_dimregion());
831 persson 1533 }
832    
833     void MainWindow::on_sel_change()
834     {
835 persson 2442 // select item in instrument menu
836 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows = m_TreeView.get_selection()->get_selected_rows();
837     if (!rows.empty()) {
838     Gtk::TreeModel::iterator it = m_refTreeModel->get_iter(rows[0]);
839     if (it) {
840     Gtk::TreePath path(it);
841     int index = path[0];
842     const std::vector<Gtk::Widget*> children =
843     instrument_menu->get_children();
844     static_cast<Gtk::RadioMenuItem*>(children[index])->set_active();
845     }
846 persson 2442 }
847    
848 persson 1533 m_RegionChooser.set_instrument(get_instrument());
849 schoenebeck 2689
850     if (Settings::singleton()->syncSamplerInstrumentSelection) {
851     switch_sampler_instrument_signal.emit(get_instrument());
852     }
853 persson 1533 }
854    
855 schoenebeck 1225 void loader_progress_callback(gig::progress_t* progress)
856     {
857     Loader* loader = static_cast<Loader*>(progress->custom);
858     loader->progress_callback(progress->factor);
859     }
860    
861     void Loader::progress_callback(float fraction)
862     {
863     {
864 persson 2325 Glib::Threads::Mutex::Lock lock(progressMutex);
865 schoenebeck 1225 progress = fraction;
866     }
867     progress_dispatcher();
868     }
869    
870 persson 3021 #if defined(WIN32) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
871     // make sure stack is 16-byte aligned for SSE instructions
872     __attribute__((force_align_arg_pointer))
873     #endif
874 schoenebeck 1225 void Loader::thread_function()
875     {
876 persson 2841 printf("thread_function self=%p\n",
877     static_cast<void*>(Glib::Threads::Thread::self()));
878 schoenebeck 2683 printf("Start %s\n", filename.c_str());
879     try {
880     RIFF::File* riff = new RIFF::File(filename);
881     gig = new gig::File(riff);
882     gig::progress_t progress;
883     progress.callback = loader_progress_callback;
884     progress.custom = this;
885 schoenebeck 1225
886 schoenebeck 2683 gig->GetInstrument(0, &progress);
887     printf("End\n");
888     finished_dispatcher();
889     } catch (RIFF::Exception e) {
890     error_message = e.Message;
891     error_dispatcher.emit();
892     } catch (...) {
893     error_message = _("Unknown exception occurred");
894     error_dispatcher.emit();
895     }
896 schoenebeck 1225 }
897    
898     Loader::Loader(const char* filename)
899 persson 2841 : filename(filename), gig(0), thread(0), progress(0.f)
900 schoenebeck 1225 {
901     }
902    
903     void Loader::launch()
904     {
905 persson 2332 #ifdef OLD_THREADS
906     thread = Glib::Thread::create(sigc::mem_fun(*this, &Loader::thread_function), true);
907     #else
908     thread = Glib::Threads::Thread::create(sigc::mem_fun(*this, &Loader::thread_function));
909     #endif
910 persson 2841 printf("launch thread=%p\n", static_cast<void*>(thread));
911 schoenebeck 1225 }
912    
913     float Loader::get_progress()
914     {
915     float res;
916     {
917 persson 2325 Glib::Threads::Mutex::Lock lock(progressMutex);
918 schoenebeck 1225 res = progress;
919     }
920     return res;
921     }
922    
923     Glib::Dispatcher& Loader::signal_progress()
924     {
925     return progress_dispatcher;
926     }
927    
928     Glib::Dispatcher& Loader::signal_finished()
929     {
930     return finished_dispatcher;
931     }
932    
933 schoenebeck 2683 Glib::Dispatcher& Loader::signal_error()
934     {
935     return error_dispatcher;
936     }
937    
938     void saver_progress_callback(gig::progress_t* progress)
939     {
940     Saver* saver = static_cast<Saver*>(progress->custom);
941     saver->progress_callback(progress->factor);
942     }
943    
944     void Saver::progress_callback(float fraction)
945     {
946     {
947     Glib::Threads::Mutex::Lock lock(progressMutex);
948     progress = fraction;
949     }
950     progress_dispatcher.emit();
951     }
952    
953 persson 3021 #if defined(WIN32) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
954     // make sure stack is 16-byte aligned for SSE instructions
955     __attribute__((force_align_arg_pointer))
956     #endif
957 schoenebeck 2683 void Saver::thread_function()
958     {
959 persson 2841 printf("thread_function self=%p\n",
960     static_cast<void*>(Glib::Threads::Thread::self()));
961 schoenebeck 2683 printf("Start %s\n", filename.c_str());
962     try {
963     gig::progress_t progress;
964     progress.callback = saver_progress_callback;
965     progress.custom = this;
966    
967     // if no filename was provided, that means "save", if filename was provided means "save as"
968     if (filename.empty()) {
969 schoenebeck 2967 if (!Settings::singleton()->saveWithTemporaryFile) {
970     // save directly over the existing .gig file
971     // (requires less disk space than solution below
972     // but may be slower)
973     gig->Save(&progress);
974     } else {
975     // save the file as separate temporary file first,
976     // then move the saved file over the old file
977     // (may result in performance speedup during save)
978     String tmpname = filename + ".TMP";
979     gig->Save(tmpname, &progress);
980     #if defined(WIN32)
981 schoenebeck 2968 if (!DeleteFile(filename.c_str())) {
982 schoenebeck 2967 throw RIFF::Exception("Could not replace original file with temporary file (unable to remove original file).");
983     }
984     #else // POSIX ...
985     if (unlink(filename.c_str())) {
986     throw RIFF::Exception("Could not replace original file with temporary file (unable to remove original file): " + String(strerror(errno)));
987     }
988     #endif
989     if (rename(tmpname.c_str(), filename.c_str())) {
990     #if defined(WIN32)
991     throw RIFF::Exception("Could not replace original file with temporary file (unable to rename temp file).");
992     #else
993     throw RIFF::Exception("Could not replace original file with temporary file (unable to rename temp file): " + String(strerror(errno)));
994     #endif
995     }
996     }
997 schoenebeck 2683 } else {
998     gig->Save(filename, &progress);
999     }
1000    
1001     printf("End\n");
1002     finished_dispatcher.emit();
1003     } catch (RIFF::Exception e) {
1004     error_message = e.Message;
1005     error_dispatcher.emit();
1006     } catch (...) {
1007     error_message = _("Unknown exception occurred");
1008     error_dispatcher.emit();
1009     }
1010     }
1011    
1012     Saver::Saver(gig::File* file, Glib::ustring filename)
1013     : gig(file), filename(filename), thread(0), progress(0.f)
1014     {
1015     }
1016    
1017     void Saver::launch()
1018     {
1019     #ifdef OLD_THREADS
1020     thread = Glib::Thread::create(sigc::mem_fun(*this, &Saver::thread_function), true);
1021     #else
1022     thread = Glib::Threads::Thread::create(sigc::mem_fun(*this, &Saver::thread_function));
1023     #endif
1024 persson 2841 printf("launch thread=%p\n", static_cast<void*>(thread));
1025 schoenebeck 2683 }
1026    
1027     float Saver::get_progress()
1028     {
1029     float res;
1030     {
1031     Glib::Threads::Mutex::Lock lock(progressMutex);
1032     res = progress;
1033     }
1034     return res;
1035     }
1036    
1037     Glib::Dispatcher& Saver::signal_progress()
1038     {
1039     return progress_dispatcher;
1040     }
1041    
1042     Glib::Dispatcher& Saver::signal_finished()
1043     {
1044     return finished_dispatcher;
1045     }
1046    
1047     Glib::Dispatcher& Saver::signal_error()
1048     {
1049     return error_dispatcher;
1050     }
1051    
1052     ProgressDialog::ProgressDialog(const Glib::ustring& title, Gtk::Window& parent)
1053 schoenebeck 1225 : Gtk::Dialog(title, parent, true)
1054     {
1055     get_vbox()->pack_start(progressBar);
1056     show_all_children();
1057 schoenebeck 2683 resize(600,50);
1058 schoenebeck 1225 }
1059    
1060     // Clear all GUI elements / controls. This method is typically called
1061     // before a new .gig file is to be created or to be loaded.
1062     void MainWindow::__clear() {
1063     // forget all samples that ought to be imported
1064     m_SampleImportQueue.clear();
1065     // clear the samples and instruments tree views
1066     m_refTreeModel->clear();
1067     m_refSamplesTreeModel->clear();
1068 schoenebeck 2615 m_refScriptsTreeModel->clear();
1069 persson 2442 // remove all entries from "Instrument" menu
1070     while (!instrument_menu->get_children().empty()) {
1071     remove_instrument_from_menu(0);
1072     }
1073 schoenebeck 1225 // free libgig's gig::File instance
1074 schoenebeck 1382 if (file && !file_is_shared) delete file;
1075     file = NULL;
1076 schoenebeck 1411 set_file_is_shared(false);
1077 schoenebeck 1225 }
1078    
1079 schoenebeck 2553 void MainWindow::__refreshEntireGUI() {
1080     // clear the samples and instruments tree views
1081     m_refTreeModel->clear();
1082     m_refSamplesTreeModel->clear();
1083 schoenebeck 2615 m_refScriptsTreeModel->clear();
1084 schoenebeck 2553 // remove all entries from "Instrument" menu
1085     while (!instrument_menu->get_children().empty()) {
1086     remove_instrument_from_menu(0);
1087     }
1088    
1089     if (!this->file) return;
1090    
1091     load_gig(
1092     this->file, this->file->pInfo->Name.c_str(), this->file_is_shared
1093     );
1094     }
1095    
1096 schoenebeck 1225 void MainWindow::on_action_file_new()
1097     {
1098 schoenebeck 1382 if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
1099 persson 1261
1100 schoenebeck 1382 if (file_is_shared && !leaving_shared_mode_dialog()) return;
1101    
1102 schoenebeck 1225 // clear all GUI elements
1103     __clear();
1104     // create a new .gig file (virtually yet)
1105     gig::File* pFile = new gig::File;
1106     // already add one new instrument by default
1107     gig::Instrument* pInstrument = pFile->AddInstrument();
1108 persson 2446 pInstrument->pInfo->Name = gig_from_utf8(_("Unnamed Instrument"));
1109 schoenebeck 1225 // update GUI with that new gig::File
1110 persson 1261 load_gig(pFile, 0 /*no file name yet*/);
1111 schoenebeck 1225 }
1112    
1113 persson 1261 bool MainWindow::close_confirmation_dialog()
1114     {
1115     gchar* msg = g_strdup_printf(_("Save changes to \"%s\" before closing?"),
1116     Glib::filename_display_basename(filename).c_str());
1117     Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
1118     g_free(msg);
1119     dialog.set_secondary_text(_("If you close without saving, your changes will be lost."));
1120     dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
1121 persson 2845 dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
1122     dialog.add_button(file_has_name ? _("_Save") : _("Save _As"), Gtk::RESPONSE_YES);
1123 persson 1261 dialog.set_default_response(Gtk::RESPONSE_YES);
1124     int response = dialog.run();
1125 persson 1303 dialog.hide();
1126 schoenebeck 2683
1127 schoenebeck 2694 // user decided to exit app without saving
1128     if (response == Gtk::RESPONSE_NO) return true;
1129    
1130     // user cancelled dialog, thus don't close app
1131     if (response == Gtk::RESPONSE_CANCEL) return false;
1132    
1133 schoenebeck 2683 // TODO: the following return valid is disabled and hard coded instead for
1134     // now, due to the fact that saving with progress bar is now implemented
1135     // asynchronously, as a result the app does not close automatically anymore
1136     // after saving the file has completed
1137     //
1138     // if (response == Gtk::RESPONSE_YES) return file_save();
1139     // return response != Gtk::RESPONSE_CANCEL;
1140     //
1141     if (response == Gtk::RESPONSE_YES) file_save();
1142     return false; // always prevent closing the app for now (see comment above)
1143 persson 1261 }
1144    
1145 schoenebeck 1382 bool MainWindow::leaving_shared_mode_dialog() {
1146     Glib::ustring msg = _("Detach from sampler and proceed working stand-alone?");
1147     Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
1148     dialog.set_secondary_text(
1149     _("If you proceed to work on another instrument file, it won't be "
1150     "used by the sampler until you tell the sampler explicitly to "
1151 persson 2151 "load it."));
1152 schoenebeck 1382 dialog.add_button(_("_Yes, Detach"), Gtk::RESPONSE_YES);
1153 persson 2845 dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
1154 schoenebeck 1382 dialog.set_default_response(Gtk::RESPONSE_CANCEL);
1155     int response = dialog.run();
1156     dialog.hide();
1157     return response == Gtk::RESPONSE_YES;
1158     }
1159    
1160 schoenebeck 1225 void MainWindow::on_action_file_open()
1161     {
1162 schoenebeck 1382 if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
1163 persson 1261
1164 schoenebeck 1382 if (file_is_shared && !leaving_shared_mode_dialog()) return;
1165    
1166 schoenebeck 1225 Gtk::FileChooserDialog dialog(*this, _("Open file"));
1167 persson 2845 dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
1168     dialog.add_button(_("_Open"), Gtk::RESPONSE_OK);
1169 persson 1261 dialog.set_default_response(Gtk::RESPONSE_OK);
1170 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1171 schoenebeck 1225 Gtk::FileFilter filter;
1172     filter.add_pattern("*.gig");
1173 persson 2169 #else
1174     Glib::RefPtr<Gtk::FileFilter> filter = Gtk::FileFilter::create();
1175     filter->add_pattern("*.gig");
1176     #endif
1177 schoenebeck 1225 dialog.set_filter(filter);
1178 persson 1725 if (current_gig_dir != "") {
1179     dialog.set_current_folder(current_gig_dir);
1180 persson 1261 }
1181 schoenebeck 1225 if (dialog.run() == Gtk::RESPONSE_OK) {
1182 persson 1261 std::string filename = dialog.get_filename();
1183     printf("filename=%s\n", filename.c_str());
1184 persson 2841 printf("on_action_file_open self=%p\n",
1185     static_cast<void*>(Glib::Threads::Thread::self()));
1186 persson 1261 load_file(filename.c_str());
1187 persson 1725 current_gig_dir = Glib::path_get_dirname(filename);
1188 schoenebeck 1225 }
1189     }
1190    
1191     void MainWindow::load_file(const char* name)
1192     {
1193 persson 1303 __clear();
1194 schoenebeck 2683
1195     progress_dialog = new ProgressDialog( //FIXME: memory leak!
1196     _("Loading") + Glib::ustring(" '") +
1197     Glib::filename_display_basename(name) + "' ...",
1198     *this
1199     );
1200     progress_dialog->show_all();
1201     loader = new Loader(name); //FIXME: memory leak!
1202 schoenebeck 1225 loader->signal_progress().connect(
1203     sigc::mem_fun(*this, &MainWindow::on_loader_progress));
1204     loader->signal_finished().connect(
1205     sigc::mem_fun(*this, &MainWindow::on_loader_finished));
1206 schoenebeck 2683 loader->signal_error().connect(
1207     sigc::mem_fun(*this, &MainWindow::on_loader_error));
1208 schoenebeck 1225 loader->launch();
1209     }
1210    
1211     void MainWindow::load_instrument(gig::Instrument* instr) {
1212     if (!instr) {
1213     Glib::ustring txt = "Provided instrument is NULL!\n";
1214     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1215     msg.run();
1216     Gtk::Main::quit();
1217     }
1218 schoenebeck 1328 // clear all GUI elements
1219     __clear();
1220     // load the instrument
1221 schoenebeck 1225 gig::File* pFile = (gig::File*) instr->GetParent();
1222 schoenebeck 1382 load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);
1223 schoenebeck 2664 // automatically select the given instrument
1224     int i = 0;
1225     for (gig::Instrument* instrument = pFile->GetFirstInstrument(); instrument;
1226     instrument = pFile->GetNextInstrument(), ++i)
1227     {
1228     if (instrument == instr) {
1229     // select item in "instruments" tree view
1230     m_TreeView.get_selection()->select(Gtk::TreePath(ToString(i)));
1231     // make sure the selected item in the "instruments" tree view is
1232     // visible (scroll to it)
1233     m_TreeView.scroll_to_row(Gtk::TreePath(ToString(i)));
1234     // select item in instrument menu
1235     {
1236     const std::vector<Gtk::Widget*> children =
1237     instrument_menu->get_children();
1238     static_cast<Gtk::RadioMenuItem*>(children[i])->set_active();
1239     }
1240     // update region chooser and dimension region chooser
1241     m_RegionChooser.set_instrument(instr);
1242     break;
1243     }
1244     }
1245 schoenebeck 1225 }
1246    
1247     void MainWindow::on_loader_progress()
1248     {
1249 schoenebeck 2683 progress_dialog->set_fraction(loader->get_progress());
1250 schoenebeck 1225 }
1251    
1252     void MainWindow::on_loader_finished()
1253     {
1254     printf("Loader finished!\n");
1255 persson 2841 printf("on_loader_finished self=%p\n",
1256     static_cast<void*>(Glib::Threads::Thread::self()));
1257 schoenebeck 2683 load_gig(loader->gig, loader->filename.c_str());
1258     progress_dialog->hide();
1259 schoenebeck 1225 }
1260    
1261 schoenebeck 2683 void MainWindow::on_loader_error()
1262     {
1263     Glib::ustring txt = _("Could not load file: ") + loader->error_message;
1264     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1265     msg.run();
1266     progress_dialog->hide();
1267     }
1268    
1269 schoenebeck 1225 void MainWindow::on_action_file_save()
1270     {
1271 persson 1261 file_save();
1272     }
1273    
1274 persson 1303 bool MainWindow::check_if_savable()
1275     {
1276     if (!file) return false;
1277    
1278     if (!file->GetFirstSample()) {
1279     Gtk::MessageDialog(*this, _("The file could not be saved "
1280     "because it contains no samples"),
1281     false, Gtk::MESSAGE_ERROR).run();
1282     return false;
1283     }
1284    
1285     for (gig::Instrument* instrument = file->GetFirstInstrument() ; instrument ;
1286     instrument = file->GetNextInstrument()) {
1287     if (!instrument->GetFirstRegion()) {
1288     Gtk::MessageDialog(*this, _("The file could not be saved "
1289     "because there are instruments "
1290     "that have no regions"),
1291     false, Gtk::MESSAGE_ERROR).run();
1292     return false;
1293     }
1294     }
1295     return true;
1296     }
1297    
1298 persson 1261 bool MainWindow::file_save()
1299     {
1300 persson 1303 if (!check_if_savable()) return false;
1301 schoenebeck 1382 if (!file_is_shared && !file_has_name) return file_save_as();
1302 persson 1261
1303 schoenebeck 1225 std::cout << "Saving file\n" << std::flush;
1304 schoenebeck 1322 file_structure_to_be_changed_signal.emit(this->file);
1305 schoenebeck 2683
1306     progress_dialog = new ProgressDialog( //FIXME: memory leak!
1307     _("Saving") + Glib::ustring(" '") +
1308     Glib::filename_display_basename(this->filename) + "' ...",
1309     *this
1310     );
1311     progress_dialog->show_all();
1312     saver = new Saver(this->file); //FIXME: memory leak!
1313     saver->signal_progress().connect(
1314     sigc::mem_fun(*this, &MainWindow::on_saver_progress));
1315     saver->signal_finished().connect(
1316     sigc::mem_fun(*this, &MainWindow::on_saver_finished));
1317     saver->signal_error().connect(
1318     sigc::mem_fun(*this, &MainWindow::on_saver_error));
1319     saver->launch();
1320    
1321     return true;
1322     }
1323    
1324     void MainWindow::on_saver_progress()
1325     {
1326     progress_dialog->set_fraction(saver->get_progress());
1327     }
1328    
1329     void MainWindow::on_saver_error()
1330     {
1331     file_structure_changed_signal.emit(this->file);
1332     Glib::ustring txt = _("Could not save file: ") + saver->error_message;
1333     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1334     msg.run();
1335     }
1336    
1337     void MainWindow::on_saver_finished()
1338     {
1339     this->file = saver->gig;
1340     this->filename = saver->filename;
1341     current_gig_dir = Glib::path_get_dirname(filename);
1342     set_title(Glib::filename_display_basename(filename));
1343     file_has_name = true;
1344     file_is_changed = false;
1345     std::cout << "Saving file done. Importing queued samples now ...\n" << std::flush;
1346 schoenebeck 1225 __import_queued_samples();
1347 schoenebeck 2683 std::cout << "Importing queued samples done.\n" << std::flush;
1348    
1349 schoenebeck 1322 file_structure_changed_signal.emit(this->file);
1350 schoenebeck 2683
1351 schoenebeck 2697 __refreshEntireGUI();
1352 schoenebeck 2683 progress_dialog->hide();
1353 schoenebeck 1225 }
1354    
1355     void MainWindow::on_action_file_save_as()
1356     {
1357 persson 1303 if (!check_if_savable()) return;
1358 persson 1261 file_save_as();
1359     }
1360    
1361     bool MainWindow::file_save_as()
1362     {
1363 persson 2845 Gtk::FileChooserDialog dialog(*this, _("Save As"), Gtk::FILE_CHOOSER_ACTION_SAVE);
1364     dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
1365     dialog.add_button(_("_Save"), Gtk::RESPONSE_OK);
1366 persson 1261 dialog.set_default_response(Gtk::RESPONSE_OK);
1367 persson 2151 dialog.set_do_overwrite_confirmation();
1368 persson 1261
1369 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1370 schoenebeck 1225 Gtk::FileFilter filter;
1371     filter.add_pattern("*.gig");
1372 persson 2169 #else
1373     Glib::RefPtr<Gtk::FileFilter> filter = Gtk::FileFilter::create();
1374     filter->add_pattern("*.gig");
1375     #endif
1376 schoenebeck 1225 dialog.set_filter(filter);
1377 persson 1261
1378 schoenebeck 1679 // set initial dir and filename of the Save As dialog
1379     // and prepare that initial filename as a copy of the gig
1380     {
1381     std::string basename = Glib::path_get_basename(filename);
1382     std::string dir = Glib::path_get_dirname(filename);
1383 persson 1831 basename = std::string(_("copy_of_")) + basename;
1384 schoenebeck 1679 Glib::ustring copyFileName = Glib::build_filename(dir, basename);
1385     if (Glib::path_is_absolute(filename)) {
1386     dialog.set_filename(copyFileName);
1387     } else {
1388 persson 1725 if (current_gig_dir != "") dialog.set_current_folder(current_gig_dir);
1389 schoenebeck 1679 }
1390     dialog.set_current_name(Glib::filename_display_basename(copyFileName));
1391 persson 1261 }
1392    
1393 schoenebeck 1679 // show warning in the dialog
1394     Gtk::HBox descriptionArea;
1395     descriptionArea.set_spacing(15);
1396 persson 2845 Gtk::Image warningIcon;
1397     warningIcon.set_from_icon_name("dialog-warning",
1398     Gtk::IconSize(Gtk::ICON_SIZE_DIALOG));
1399 schoenebeck 1679 descriptionArea.pack_start(warningIcon, Gtk::PACK_SHRINK);
1400 persson 2344 #if GTKMM_MAJOR_VERSION < 3
1401 persson 1799 view::WrapLabel description;
1402 persson 2344 #else
1403     Gtk::Label description;
1404     description.set_line_wrap();
1405     #endif
1406 schoenebeck 1679 description.set_markup(
1407     _("\n<b>CAUTION:</b> You <b>MUST</b> use the "
1408     "<span style=\"italic\">\"Save\"</span> dialog instead of "
1409     "<span style=\"italic\">\"Save As...\"</span> if you want to save "
1410     "to the same .gig file. Using "
1411     "<span style=\"italic\">\"Save As...\"</span> for writing to the "
1412     "same .gig file will end up in corrupted sample wave data!\n")
1413     );
1414 persson 1799 descriptionArea.pack_start(description);
1415 schoenebeck 1679 dialog.get_vbox()->pack_start(descriptionArea, Gtk::PACK_SHRINK);
1416 persson 1799 descriptionArea.show_all();
1417 schoenebeck 1679
1418 schoenebeck 1225 if (dialog.run() == Gtk::RESPONSE_OK) {
1419 schoenebeck 2683 std::string filename = dialog.get_filename();
1420     if (!Glib::str_has_suffix(filename, ".gig")) {
1421     filename += ".gig";
1422 schoenebeck 1225 }
1423 schoenebeck 2683 printf("filename=%s\n", filename.c_str());
1424    
1425     progress_dialog = new ProgressDialog( //FIXME: memory leak!
1426     _("Saving") + Glib::ustring(" '") +
1427     Glib::filename_display_basename(filename) + "' ...",
1428     *this
1429     );
1430     progress_dialog->show_all();
1431    
1432     saver = new Saver(file, filename); //FIXME: memory leak!
1433     saver->signal_progress().connect(
1434     sigc::mem_fun(*this, &MainWindow::on_saver_progress));
1435     saver->signal_finished().connect(
1436     sigc::mem_fun(*this, &MainWindow::on_saver_finished));
1437     saver->signal_error().connect(
1438     sigc::mem_fun(*this, &MainWindow::on_saver_error));
1439     saver->launch();
1440    
1441 persson 1261 return true;
1442 schoenebeck 1225 }
1443 persson 1261 return false;
1444 schoenebeck 1225 }
1445    
1446     // actually write the sample(s)' data to the gig file
1447     void MainWindow::__import_queued_samples() {
1448     std::cout << "Starting sample import\n" << std::flush;
1449     Glib::ustring error_files;
1450 persson 2841 printf("Samples to import: %d\n", int(m_SampleImportQueue.size()));
1451 schoenebeck 1225 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1452     iter != m_SampleImportQueue.end(); ) {
1453     printf("Importing sample %s\n",(*iter).sample_path.c_str());
1454     SF_INFO info;
1455     info.format = 0;
1456     SNDFILE* hFile = sf_open((*iter).sample_path.c_str(), SFM_READ, &info);
1457 persson 2398 sf_command(hFile, SFC_SET_SCALE_FLOAT_INT_READ, 0, SF_TRUE);
1458 schoenebeck 1225 try {
1459 persson 1831 if (!hFile) throw std::string(_("could not open file"));
1460 schoenebeck 1225 // determine sample's bit depth
1461     int bitdepth;
1462     switch (info.format & 0xff) {
1463     case SF_FORMAT_PCM_S8:
1464     case SF_FORMAT_PCM_16:
1465 persson 1265 case SF_FORMAT_PCM_U8:
1466 schoenebeck 1225 bitdepth = 16;
1467     break;
1468     case SF_FORMAT_PCM_24:
1469     case SF_FORMAT_PCM_32:
1470     case SF_FORMAT_FLOAT:
1471     case SF_FORMAT_DOUBLE:
1472 persson 1265 bitdepth = 24;
1473 schoenebeck 1225 break;
1474     default:
1475     sf_close(hFile); // close sound file
1476 persson 1831 throw std::string(_("format not supported")); // unsupported subformat (yet?)
1477 schoenebeck 1225 }
1478 persson 1265
1479     const int bufsize = 10000;
1480 schoenebeck 1225 switch (bitdepth) {
1481 persson 1265 case 16: {
1482     short* buffer = new short[bufsize * info.channels];
1483     sf_count_t cnt = info.frames;
1484     while (cnt) {
1485     // libsndfile does the conversion for us (if needed)
1486     int n = sf_readf_short(hFile, buffer, bufsize);
1487     // write from buffer directly (physically) into .gig file
1488     iter->gig_sample->Write(buffer, n);
1489     cnt -= n;
1490     }
1491     delete[] buffer;
1492 schoenebeck 1225 break;
1493 persson 1265 }
1494     case 24: {
1495     int* srcbuf = new int[bufsize * info.channels];
1496     uint8_t* dstbuf = new uint8_t[bufsize * 3 * info.channels];
1497     sf_count_t cnt = info.frames;
1498     while (cnt) {
1499     // libsndfile returns 32 bits, convert to 24
1500     int n = sf_readf_int(hFile, srcbuf, bufsize);
1501     int j = 0;
1502     for (int i = 0 ; i < n * info.channels ; i++) {
1503     dstbuf[j++] = srcbuf[i] >> 8;
1504     dstbuf[j++] = srcbuf[i] >> 16;
1505     dstbuf[j++] = srcbuf[i] >> 24;
1506     }
1507     // write from buffer directly (physically) into .gig file
1508     iter->gig_sample->Write(dstbuf, n);
1509     cnt -= n;
1510     }
1511     delete[] srcbuf;
1512     delete[] dstbuf;
1513 schoenebeck 1225 break;
1514 persson 1265 }
1515 schoenebeck 1225 }
1516     // cleanup
1517     sf_close(hFile);
1518 schoenebeck 1853 // let the sampler re-cache the sample if needed
1519     sample_changed_signal.emit(iter->gig_sample);
1520 schoenebeck 1225 // on success we remove the sample from the import queue,
1521     // otherwise keep it, maybe it works the next time ?
1522     std::list<SampleImportItem>::iterator cur = iter;
1523     ++iter;
1524     m_SampleImportQueue.erase(cur);
1525     } catch (std::string what) {
1526     // remember the files that made trouble (and their cause)
1527 persson 2442 if (!error_files.empty()) error_files += "\n";
1528 schoenebeck 1225 error_files += (*iter).sample_path += " (" + what + ")";
1529     ++iter;
1530     }
1531     }
1532     // show error message box when some sample(s) could not be imported
1533 persson 2442 if (!error_files.empty()) {
1534 schoenebeck 1382 Glib::ustring txt = _("Could not import the following sample(s):\n") + error_files;
1535 schoenebeck 1225 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1536     msg.run();
1537     }
1538     }
1539    
1540     void MainWindow::on_action_file_properties()
1541     {
1542     propDialog.show();
1543     propDialog.deiconify();
1544     }
1545    
1546 schoenebeck 2541 void MainWindow::on_action_warn_user_on_extensions() {
1547     Settings::singleton()->warnUserOnExtensions =
1548     !Settings::singleton()->warnUserOnExtensions;
1549     }
1550    
1551 schoenebeck 2689 void MainWindow::on_action_sync_sampler_instrument_selection() {
1552     Settings::singleton()->syncSamplerInstrumentSelection =
1553     !Settings::singleton()->syncSamplerInstrumentSelection;
1554     }
1555    
1556 schoenebeck 2773 void MainWindow::on_action_move_root_note_with_region_moved() {
1557     Settings::singleton()->moveRootNoteWithRegionMoved =
1558     !Settings::singleton()->moveRootNoteWithRegionMoved;
1559     }
1560    
1561 schoenebeck 1225 void MainWindow::on_action_help_about()
1562     {
1563     Gtk::AboutDialog dialog;
1564 persson 1959 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 12) || GTKMM_MAJOR_VERSION > 2
1565     dialog.set_program_name("Gigedit");
1566     #else
1567     dialog.set_name("Gigedit");
1568     #endif
1569 schoenebeck 1225 dialog.set_version(VERSION);
1570 schoenebeck 3089 dialog.set_copyright("Copyright (C) 2006-2017 Andreas Persson");
1571 schoenebeck 2476 const std::string sComment =
1572     _("Built " __DATE__ "\nUsing ") +
1573     ::gig::libraryName() + " " + ::gig::libraryVersion() + "\n\n" +
1574     _(
1575     "Gigedit is released under the GNU General Public License.\n"
1576     "\n"
1577 schoenebeck 2627 "This program is distributed WITHOUT ANY WARRANTY; So better "
1578     "backup your Gigasampler/GigaStudio files before editing them with "
1579 schoenebeck 2476 "this application.\n"
1580     "\n"
1581     "Please report bugs to: http://bugs.linuxsampler.org"
1582     );
1583     dialog.set_comments(sComment.c_str());
1584 schoenebeck 1436 dialog.set_website("http://www.linuxsampler.org");
1585     dialog.set_website_label("http://www.linuxsampler.org");
1586 schoenebeck 1225 dialog.run();
1587     }
1588    
1589     PropDialog::PropDialog()
1590 schoenebeck 2560 : eFileFormat(_("File Format")),
1591     eName(_("Name")),
1592 persson 1831 eCreationDate(_("Creation date")),
1593     eComments(_("Comments")),
1594     eProduct(_("Product")),
1595     eCopyright(_("Copyright")),
1596     eArtists(_("Artists")),
1597     eGenre(_("Genre")),
1598     eKeywords(_("Keywords")),
1599     eEngineer(_("Engineer")),
1600     eTechnician(_("Technician")),
1601     eSoftware(_("Software")),
1602     eMedium(_("Medium")),
1603     eSource(_("Source")),
1604     eSourceForm(_("Source form")),
1605     eCommissioned(_("Commissioned")),
1606     eSubject(_("Subject")),
1607 persson 2845 quitButton(_("_Close"), true),
1608 schoenebeck 2560 table(2, 1),
1609     m_file(NULL)
1610 schoenebeck 1225 {
1611 persson 1831 set_title(_("File Properties"));
1612 persson 1582 eName.set_width_chars(50);
1613    
1614     connect(eName, &DLS::Info::Name);
1615     connect(eCreationDate, &DLS::Info::CreationDate);
1616     connect(eComments, &DLS::Info::Comments);
1617     connect(eProduct, &DLS::Info::Product);
1618     connect(eCopyright, &DLS::Info::Copyright);
1619     connect(eArtists, &DLS::Info::Artists);
1620     connect(eGenre, &DLS::Info::Genre);
1621     connect(eKeywords, &DLS::Info::Keywords);
1622     connect(eEngineer, &DLS::Info::Engineer);
1623     connect(eTechnician, &DLS::Info::Technician);
1624     connect(eSoftware, &DLS::Info::Software);
1625     connect(eMedium, &DLS::Info::Medium);
1626     connect(eSource, &DLS::Info::Source);
1627     connect(eSourceForm, &DLS::Info::SourceForm);
1628     connect(eCommissioned, &DLS::Info::Commissioned);
1629     connect(eSubject, &DLS::Info::Subject);
1630    
1631 schoenebeck 2560 table.add(eFileFormat);
1632 persson 1582 table.add(eName);
1633     table.add(eCreationDate);
1634     table.add(eComments);
1635     table.add(eProduct);
1636     table.add(eCopyright);
1637     table.add(eArtists);
1638     table.add(eGenre);
1639     table.add(eKeywords);
1640     table.add(eEngineer);
1641     table.add(eTechnician);
1642     table.add(eSoftware);
1643     table.add(eMedium);
1644     table.add(eSource);
1645     table.add(eSourceForm);
1646     table.add(eCommissioned);
1647     table.add(eSubject);
1648    
1649 schoenebeck 1225 table.set_col_spacings(5);
1650 persson 1582 add(vbox);
1651     table.set_border_width(5);
1652     vbox.add(table);
1653     vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
1654     buttonBox.set_layout(Gtk::BUTTONBOX_END);
1655     buttonBox.set_border_width(5);
1656     buttonBox.show();
1657     buttonBox.pack_start(quitButton);
1658 persson 2151 quitButton.set_can_default();
1659 persson 1582 quitButton.grab_focus();
1660     quitButton.signal_clicked().connect(
1661     sigc::mem_fun(*this, &PropDialog::hide));
1662 schoenebeck 2560 eFileFormat.signal_value_changed().connect(
1663     sigc::mem_fun(*this, &PropDialog::onFileFormatChanged));
1664 schoenebeck 1225
1665 persson 1582 quitButton.show();
1666     vbox.show();
1667 schoenebeck 1225 show_all_children();
1668     }
1669    
1670 schoenebeck 2560 void PropDialog::set_file(gig::File* file)
1671     {
1672     m_file = file;
1673    
1674     // update file format version combo box
1675     const std::string sGiga = "Gigasampler/GigaStudio v";
1676     const int major = file->pVersion->major;
1677     std::vector<std::string> txts;
1678     std::vector<int> values;
1679     txts.push_back(sGiga + "2"); values.push_back(2);
1680 schoenebeck 2566 txts.push_back(sGiga + "3/v4"); values.push_back(3);
1681 schoenebeck 2560 if (major != 2 && major != 3) {
1682     txts.push_back(sGiga + ToString(major)); values.push_back(major);
1683     }
1684     std::vector<const char*> texts;
1685     for (int i = 0; i < txts.size(); ++i) texts.push_back(txts[i].c_str());
1686 persson 2579 texts.push_back(NULL); values.push_back(0);
1687 schoenebeck 2560 eFileFormat.set_choices(&texts[0], &values[0]);
1688     eFileFormat.set_value(major);
1689     }
1690    
1691     void PropDialog::onFileFormatChanged() {
1692     const int major = eFileFormat.get_value();
1693     if (m_file) m_file->pVersion->major = major;
1694     }
1695    
1696 schoenebeck 1225 void PropDialog::set_info(DLS::Info* info)
1697     {
1698 persson 2423 update(info);
1699 schoenebeck 1225 }
1700    
1701 persson 1582
1702 persson 2445 void InstrumentProps::set_Name(const gig::String& name)
1703     {
1704     m->pInfo->Name = name;
1705     }
1706    
1707     void InstrumentProps::update_name()
1708     {
1709     update_model++;
1710     eName.set_value(m->pInfo->Name);
1711     update_model--;
1712     }
1713    
1714 persson 1460 void InstrumentProps::set_IsDrum(bool value)
1715     {
1716 persson 2423 m->IsDrum = value;
1717 persson 1460 }
1718    
1719     void InstrumentProps::set_MIDIBank(uint16_t value)
1720     {
1721 persson 2423 m->MIDIBank = value;
1722 persson 1460 }
1723    
1724     void InstrumentProps::set_MIDIProgram(uint32_t value)
1725     {
1726 persson 2423 m->MIDIProgram = value;
1727 persson 1460 }
1728    
1729 persson 2423 InstrumentProps::InstrumentProps() :
1730 persson 2845 quitButton(_("_Close"), true),
1731 persson 2423 table(2,1),
1732     eName(_("Name")),
1733     eIsDrum(_("Is drum")),
1734     eMIDIBank(_("MIDI bank"), 0, 16383),
1735     eMIDIProgram(_("MIDI program")),
1736     eAttenuation(_("Attenuation"), 0, 96, 0, 1),
1737     eGainPlus6(_("Gain +6dB"), eAttenuation, -6),
1738     eEffectSend(_("Effect send"), 0, 65535),
1739     eFineTune(_("Fine tune"), -8400, 8400),
1740     ePitchbendRange(_("Pitchbend range"), 0, 12),
1741     ePianoReleaseMode(_("Piano release mode")),
1742     eDimensionKeyRangeLow(_("Keyswitching range low")),
1743     eDimensionKeyRangeHigh(_("Keyswitching range high"))
1744 persson 1460 {
1745 persson 1831 set_title(_("Instrument Properties"));
1746 schoenebeck 1225
1747 schoenebeck 1656 eDimensionKeyRangeLow.set_tip(
1748     _("start of the keyboard area which should switch the "
1749     "\"keyswitching\" dimension")
1750     );
1751     eDimensionKeyRangeHigh.set_tip(
1752     _("end of the keyboard area which should switch the "
1753     "\"keyswitching\" dimension")
1754     );
1755    
1756 persson 2445 connect(eName, &InstrumentProps::set_Name);
1757 persson 1460 connect(eIsDrum, &InstrumentProps::set_IsDrum);
1758     connect(eMIDIBank, &InstrumentProps::set_MIDIBank);
1759     connect(eMIDIProgram, &InstrumentProps::set_MIDIProgram);
1760     connect(eAttenuation, &gig::Instrument::Attenuation);
1761     connect(eGainPlus6, &gig::Instrument::Attenuation);
1762     connect(eEffectSend, &gig::Instrument::EffectSend);
1763     connect(eFineTune, &gig::Instrument::FineTune);
1764     connect(ePitchbendRange, &gig::Instrument::PitchbendRange);
1765     connect(ePianoReleaseMode, &gig::Instrument::PianoReleaseMode);
1766 persson 2423 connect(eDimensionKeyRangeLow, eDimensionKeyRangeHigh,
1767     &gig::Instrument::DimensionKeyRange);
1768 persson 1460
1769 persson 2445 eName.signal_value_changed().connect(sig_name_changed.make_slot());
1770    
1771 schoenebeck 1225 table.set_col_spacings(5);
1772    
1773 persson 1582 table.add(eName);
1774     table.add(eIsDrum);
1775     table.add(eMIDIBank);
1776     table.add(eMIDIProgram);
1777     table.add(eAttenuation);
1778     table.add(eGainPlus6);
1779     table.add(eEffectSend);
1780     table.add(eFineTune);
1781     table.add(ePitchbendRange);
1782     table.add(ePianoReleaseMode);
1783     table.add(eDimensionKeyRangeLow);
1784     table.add(eDimensionKeyRangeHigh);
1785 schoenebeck 1225
1786     add(vbox);
1787     table.set_border_width(5);
1788     vbox.pack_start(table);
1789     table.show();
1790     vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
1791     buttonBox.set_layout(Gtk::BUTTONBOX_END);
1792     buttonBox.set_border_width(5);
1793     buttonBox.show();
1794     buttonBox.pack_start(quitButton);
1795 persson 2151 quitButton.set_can_default();
1796 schoenebeck 1225 quitButton.grab_focus();
1797    
1798     quitButton.signal_clicked().connect(
1799     sigc::mem_fun(*this, &InstrumentProps::hide));
1800    
1801     quitButton.show();
1802     vbox.show();
1803     show_all_children();
1804     }
1805    
1806     void InstrumentProps::set_instrument(gig::Instrument* instrument)
1807     {
1808 persson 2423 update(instrument);
1809 persson 1460
1810     update_model++;
1811 persson 2445 eName.set_value(instrument->pInfo->Name);
1812 persson 1460 eIsDrum.set_value(instrument->IsDrum);
1813     eMIDIBank.set_value(instrument->MIDIBank);
1814     eMIDIProgram.set_value(instrument->MIDIProgram);
1815     update_model--;
1816 schoenebeck 1225 }
1817    
1818    
1819 persson 1261 void MainWindow::file_changed()
1820     {
1821     if (file && !file_is_changed) {
1822     set_title("*" + get_title());
1823     file_is_changed = true;
1824 schoenebeck 1225 }
1825 persson 1261 }
1826 schoenebeck 1225
1827 schoenebeck 2621 void MainWindow::updateSampleRefCountMap(gig::File* gig) {
1828     sample_ref_count.clear();
1829    
1830     if (!gig) return;
1831    
1832     for (gig::Instrument* instrument = gig->GetFirstInstrument(); instrument;
1833     instrument = gig->GetNextInstrument())
1834     {
1835     for (gig::Region* rgn = instrument->GetFirstRegion(); rgn;
1836     rgn = instrument->GetNextRegion())
1837     {
1838     for (int i = 0; i < 256; ++i) {
1839     if (!rgn->pDimensionRegions[i]) continue;
1840     if (rgn->pDimensionRegions[i]->pSample) {
1841     sample_ref_count[rgn->pDimensionRegions[i]->pSample]++;
1842     }
1843     }
1844     }
1845     }
1846     }
1847    
1848 schoenebeck 1382 void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)
1849 persson 1261 {
1850     file = 0;
1851 schoenebeck 1411 set_file_is_shared(isSharedInstrument);
1852 persson 1261
1853 schoenebeck 2772 this->filename =
1854     (filename && strlen(filename) > 0) ?
1855     filename : (!gig->GetFileName().empty()) ?
1856     gig->GetFileName() : _("Unsaved Gig File");
1857 persson 1261 set_title(Glib::filename_display_basename(this->filename));
1858     file_has_name = filename;
1859     file_is_changed = false;
1860    
1861 schoenebeck 2560 propDialog.set_file(gig);
1862 schoenebeck 1225 propDialog.set_info(gig->pInfo);
1863    
1864 persson 2442 instrument_name_connection.block();
1865 schoenebeck 2994 int index = 0;
1866 schoenebeck 1225 for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;
1867 schoenebeck 2994 instrument = gig->GetNextInstrument(), ++index) {
1868 persson 2446 Glib::ustring name(gig_to_utf8(instrument->pInfo->Name));
1869 persson 2442
1870 schoenebeck 1225 Gtk::TreeModel::iterator iter = m_refTreeModel->append();
1871     Gtk::TreeModel::Row row = *iter;
1872 schoenebeck 2994 row[m_Columns.m_col_nr] = index;
1873 persson 2442 row[m_Columns.m_col_name] = name;
1874 schoenebeck 1225 row[m_Columns.m_col_instr] = instrument;
1875 persson 2442
1876     add_instrument_to_menu(name);
1877 schoenebeck 1225 }
1878 persson 2442 instrument_name_connection.unblock();
1879 schoenebeck 2625 uiManager->get_widget("/MenuBar/MenuInstrument/AllInstruments")->show();
1880 schoenebeck 1225
1881 schoenebeck 2621 updateSampleRefCountMap(gig);
1882    
1883 schoenebeck 1225 for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
1884     if (group->Name != "") {
1885     Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1886     Gtk::TreeModel::Row rowGroup = *iterGroup;
1887 persson 2446 rowGroup[m_SamplesModel.m_col_name] = gig_to_utf8(group->Name);
1888 schoenebeck 1225 rowGroup[m_SamplesModel.m_col_group] = group;
1889     rowGroup[m_SamplesModel.m_col_sample] = NULL;
1890     for (gig::Sample* sample = group->GetFirstSample();
1891     sample; sample = group->GetNextSample()) {
1892     Gtk::TreeModel::iterator iterSample =
1893     m_refSamplesTreeModel->append(rowGroup.children());
1894     Gtk::TreeModel::Row rowSample = *iterSample;
1895 persson 2446 rowSample[m_SamplesModel.m_col_name] =
1896     gig_to_utf8(sample->pInfo->Name);
1897 schoenebeck 1225 rowSample[m_SamplesModel.m_col_sample] = sample;
1898     rowSample[m_SamplesModel.m_col_group] = NULL;
1899 schoenebeck 2621 int refcount = sample_ref_count.count(sample) ? sample_ref_count[sample] : 0;
1900     rowSample[m_SamplesModel.m_col_refcount] = ToString(refcount) + " " + _("Refs.");
1901 schoenebeck 2625 rowSample[m_SamplesModel.m_color] = refcount ? "black" : "red";
1902 schoenebeck 1225 }
1903     }
1904     }
1905 schoenebeck 2604
1906     for (int i = 0; gig->GetScriptGroup(i); ++i) {
1907     gig::ScriptGroup* group = gig->GetScriptGroup(i);
1908 schoenebeck 1225
1909 schoenebeck 2604 Gtk::TreeModel::iterator iterGroup = m_refScriptsTreeModel->append();
1910     Gtk::TreeModel::Row rowGroup = *iterGroup;
1911     rowGroup[m_ScriptsModel.m_col_name] = gig_to_utf8(group->Name);
1912     rowGroup[m_ScriptsModel.m_col_group] = group;
1913     rowGroup[m_ScriptsModel.m_col_script] = NULL;
1914     for (int s = 0; group->GetScript(s); ++s) {
1915     gig::Script* script = group->GetScript(s);
1916    
1917     Gtk::TreeModel::iterator iterScript =
1918     m_refScriptsTreeModel->append(rowGroup.children());
1919     Gtk::TreeModel::Row rowScript = *iterScript;
1920     rowScript[m_ScriptsModel.m_col_name] = gig_to_utf8(script->Name);
1921     rowScript[m_ScriptsModel.m_col_script] = script;
1922     rowScript[m_ScriptsModel.m_col_group] = NULL;
1923     }
1924     }
1925 schoenebeck 2624 // unfold all sample groups & script groups by default
1926     m_TreeViewSamples.expand_all();
1927 schoenebeck 2604 m_TreeViewScripts.expand_all();
1928    
1929 persson 1261 file = gig;
1930    
1931 schoenebeck 1225 // select the first instrument
1932 persson 2442 m_TreeView.get_selection()->select(Gtk::TreePath("0"));
1933 persson 2423
1934 persson 2445 instr_props_set_instrument();
1935 persson 2507 gig::Instrument* instrument = get_instrument();
1936     if (instrument) {
1937     midiRules.set_instrument(instrument);
1938     }
1939 persson 2445 }
1940    
1941     bool MainWindow::instr_props_set_instrument()
1942     {
1943     instrumentProps.signal_name_changed().clear();
1944    
1945 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows = m_TreeView.get_selection()->get_selected_rows();
1946     if (rows.empty()) {
1947     instrumentProps.hide();
1948     return false;
1949     }
1950     Gtk::TreeModel::const_iterator it = m_refTreeModel->get_iter(rows[0]);
1951 persson 2445 if (it) {
1952     Gtk::TreeModel::Row row = *it;
1953     gig::Instrument* instrument = row[m_Columns.m_col_instr];
1954    
1955 persson 2423 instrumentProps.set_instrument(instrument);
1956 persson 2445
1957     // make sure instrument tree is updated when user changes the
1958     // instrument name in instrument properties window
1959     instrumentProps.signal_name_changed().connect(
1960     sigc::bind(
1961     sigc::mem_fun(*this,
1962     &MainWindow::instr_name_changed_by_instr_props),
1963     it));
1964     } else {
1965     instrumentProps.hide();
1966 persson 2423 }
1967 persson 2445 return it;
1968 schoenebeck 1225 }
1969    
1970     void MainWindow::show_instr_props()
1971     {
1972 persson 2445 if (instr_props_set_instrument()) {
1973 persson 1533 instrumentProps.show();
1974     instrumentProps.deiconify();
1975 schoenebeck 1225 }
1976     }
1977    
1978 persson 2445 void MainWindow::instr_name_changed_by_instr_props(Gtk::TreeModel::iterator& it)
1979     {
1980     Gtk::TreeModel::Row row = *it;
1981     Glib::ustring name = row[m_Columns.m_col_name];
1982    
1983     gig::Instrument* instrument = row[m_Columns.m_col_instr];
1984 persson 2446 Glib::ustring gigname(gig_to_utf8(instrument->pInfo->Name));
1985     if (gigname != name) {
1986     row[m_Columns.m_col_name] = gigname;
1987 persson 2445 }
1988     }
1989    
1990 persson 2507 void MainWindow::show_midi_rules()
1991     {
1992     if (gig::Instrument* instrument = get_instrument())
1993     {
1994     midiRules.set_instrument(instrument);
1995     midiRules.show();
1996     midiRules.deiconify();
1997     }
1998     }
1999    
2000 schoenebeck 2610 void MainWindow::show_script_slots() {
2001     if (!file) return;
2002     // get selected instrument
2003 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows = m_TreeView.get_selection()->get_selected_rows();
2004     if (rows.empty()) return;
2005     Gtk::TreeModel::iterator it = m_refTreeModel->get_iter(rows[0]);
2006 schoenebeck 2610 if (!it) return;
2007     Gtk::TreeModel::Row row = *it;
2008     gig::Instrument* instrument = row[m_Columns.m_col_instr];
2009     if (!instrument) return;
2010    
2011     ScriptSlots* window = new ScriptSlots;
2012     window->setInstrument(instrument);
2013     //window->reparent(*this);
2014     window->show();
2015     }
2016    
2017 schoenebeck 2772 void MainWindow::on_action_refresh_all() {
2018     __refreshEntireGUI();
2019     }
2020    
2021 schoenebeck 1415 void MainWindow::on_action_view_status_bar() {
2022     Gtk::CheckMenuItem* item =
2023     dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuView/Statusbar"));
2024     if (!item) {
2025     std::cerr << "/MenuBar/MenuView/Statusbar == NULL\n";
2026     return;
2027     }
2028     if (item->get_active()) m_StatusBar.show();
2029     else m_StatusBar.hide();
2030     }
2031    
2032 schoenebeck 2918 void MainWindow::on_auto_restore_win_dim() {
2033     Gtk::CheckMenuItem* item =
2034     dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuView/AutoRestoreWinDim"));
2035     if (!item) {
2036     std::cerr << "/MenuBar/MenuView/AutoRestoreWinDim == NULL\n";
2037     return;
2038     }
2039     Settings::singleton()->autoRestoreWindowDimension = item->get_active();
2040     }
2041    
2042 schoenebeck 2967 void MainWindow::on_save_with_temporary_file() {
2043     Gtk::CheckMenuItem* item =
2044     dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuSettings/SaveWithTemporaryFile"));
2045     if (!item) {
2046     std::cerr << "/MenuBar/MenuSettings/SaveWithTemporaryFile == NULL\n";
2047     return;
2048     }
2049     Settings::singleton()->saveWithTemporaryFile = item->get_active();
2050     }
2051    
2052 schoenebeck 2464 bool MainWindow::is_copy_samples_unity_note_enabled() const {
2053     Gtk::CheckMenuItem* item =
2054     dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuEdit/CopySampleUnity"));
2055     if (!item) {
2056     std::cerr << "/MenuBar/MenuEdit/CopySampleUnity == NULL\n";
2057     return true;
2058     }
2059     return item->get_active();
2060     }
2061    
2062     bool MainWindow::is_copy_samples_fine_tune_enabled() const {
2063     Gtk::CheckMenuItem* item =
2064     dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuEdit/CopySampleTune"));
2065     if (!item) {
2066     std::cerr << "/MenuBar/MenuEdit/CopySampleTune == NULL\n";
2067     return true;
2068     }
2069     return item->get_active();
2070     }
2071    
2072     bool MainWindow::is_copy_samples_loop_enabled() const {
2073     Gtk::CheckMenuItem* item =
2074     dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuEdit/CopySampleLoop"));
2075     if (!item) {
2076     std::cerr << "/MenuBar/MenuEdit/CopySampleLoop == NULL\n";
2077     return true;
2078     }
2079     return item->get_active();
2080     }
2081    
2082 schoenebeck 1225 void MainWindow::on_button_release(GdkEventButton* button)
2083     {
2084     if (button->type == GDK_2BUTTON_PRESS) {
2085     show_instr_props();
2086     } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
2087 persson 2507 // gig v2 files have no midi rules
2088 schoenebeck 2625 const bool bEnabled = !(file->pVersion && file->pVersion->major == 2);
2089 persson 2507 static_cast<Gtk::MenuItem*>(
2090 schoenebeck 2625 uiManager->get_widget("/MenuBar/MenuInstrument/MidiRules"))->set_sensitive(
2091     bEnabled
2092     );
2093     static_cast<Gtk::MenuItem*>(
2094 persson 2507 uiManager->get_widget("/PopupMenu/MidiRules"))->set_sensitive(
2095 schoenebeck 2625 bEnabled
2096     );
2097 schoenebeck 1225 popup_menu->popup(button->button, button->time);
2098     }
2099     }
2100    
2101 persson 2442 void MainWindow::on_instrument_selection_change(Gtk::RadioMenuItem* item) {
2102     if (item->get_active()) {
2103     const std::vector<Gtk::Widget*> children =
2104     instrument_menu->get_children();
2105     std::vector<Gtk::Widget*>::const_iterator it =
2106     find(children.begin(), children.end(), item);
2107     if (it != children.end()) {
2108     int index = it - children.begin();
2109     m_TreeView.get_selection()->select(Gtk::TreePath(ToString(index)));
2110    
2111     m_RegionChooser.set_instrument(file->GetInstrument(index));
2112     }
2113     }
2114 schoenebeck 1225 }
2115    
2116 schoenebeck 2701 void MainWindow::select_instrument(gig::Instrument* instrument) {
2117     if (!instrument) return;
2118    
2119     Glib::RefPtr<Gtk::TreeModel> model = m_TreeView.get_model();
2120     for (int i = 0; i < model->children().size(); ++i) {
2121     Gtk::TreeModel::Row row = model->children()[i];
2122     if (row[m_Columns.m_col_instr] == instrument) {
2123     // select and show the respective instrument in the list view
2124     show_intruments_tab();
2125 schoenebeck 2994 m_TreeView.get_selection()->unselect_all();
2126 schoenebeck 2701 m_TreeView.get_selection()->select(model->children()[i]);
2127 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows =
2128     m_TreeView.get_selection()->get_selected_rows();
2129     if (!rows.empty())
2130     m_TreeView.scroll_to_row(rows[0]);
2131 schoenebeck 2701 on_sel_change(); // the regular instrument selection change callback
2132     }
2133     }
2134     }
2135    
2136 schoenebeck 2695 /// Returns true if requested dimension region was successfully selected and scrolled to in the list view, false on error.
2137     bool MainWindow::select_dimension_region(gig::DimensionRegion* dimRgn) {
2138     gig::Region* pRegion = (gig::Region*) dimRgn->GetParent();
2139     gig::Instrument* pInstrument = (gig::Instrument*) pRegion->GetParent();
2140    
2141     Glib::RefPtr<Gtk::TreeModel> model = m_TreeView.get_model();
2142     for (int i = 0; i < model->children().size(); ++i) {
2143     Gtk::TreeModel::Row row = model->children()[i];
2144     if (row[m_Columns.m_col_instr] == pInstrument) {
2145     // select and show the respective instrument in the list view
2146     show_intruments_tab();
2147 schoenebeck 2994 m_TreeView.get_selection()->unselect_all();
2148 schoenebeck 2695 m_TreeView.get_selection()->select(model->children()[i]);
2149 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows =
2150     m_TreeView.get_selection()->get_selected_rows();
2151     if (!rows.empty())
2152     m_TreeView.scroll_to_row(rows[0]);
2153 schoenebeck 2695 on_sel_change(); // the regular instrument selection change callback
2154    
2155     // select respective region in the region selector
2156     m_RegionChooser.set_region(pRegion);
2157    
2158     // select and show the respective dimension region in the editor
2159     //update_dimregs();
2160     if (!m_DimRegionChooser.select_dimregion(dimRgn)) return false;
2161     //dimreg_edit.set_dim_region(dimRgn);
2162    
2163     return true;
2164     }
2165     }
2166    
2167     return false;
2168     }
2169    
2170 schoenebeck 2691 void MainWindow::select_sample(gig::Sample* sample) {
2171     Glib::RefPtr<Gtk::TreeModel> model = m_TreeViewSamples.get_model();
2172     for (int g = 0; g < model->children().size(); ++g) {
2173     Gtk::TreeModel::Row rowGroup = model->children()[g];
2174     for (int s = 0; s < rowGroup.children().size(); ++s) {
2175     Gtk::TreeModel::Row rowSample = rowGroup.children()[s];
2176     if (rowSample[m_SamplesModel.m_col_sample] == sample) {
2177     show_samples_tab();
2178 schoenebeck 2994 m_TreeViewSamples.get_selection()->unselect_all();
2179 schoenebeck 2691 m_TreeViewSamples.get_selection()->select(rowGroup.children()[s]);
2180 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows =
2181     m_TreeViewSamples.get_selection()->get_selected_rows();
2182     if (rows.empty()) return;
2183     m_TreeViewSamples.scroll_to_row(rows[0]);
2184 schoenebeck 2691 return;
2185     }
2186     }
2187     }
2188     }
2189    
2190 schoenebeck 1225 void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {
2191     if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
2192 schoenebeck 2994 // by default if Ctrl keys is pressed down, then a mouse right-click
2193     // does not select the respective row, so we must assure this
2194     // programmatically ...
2195     /*{
2196     Gtk::TreeModel::Path path;
2197     Gtk::TreeViewColumn* pColumn = NULL;
2198     int cellX, cellY;
2199     bool bSuccess = m_TreeViewSamples.get_path_at_pos(
2200     (int)button->x, (int)button->y,
2201     path, pColumn, cellX, cellY
2202     );
2203     if (bSuccess) {
2204     if (m_TreeViewSamples.get_selection()->count_selected_rows() <= 0) {
2205     printf("not selected !!!\n");
2206     m_TreeViewSamples.get_selection()->select(path);
2207     }
2208     }
2209     }*/
2210    
2211 schoenebeck 1225 Gtk::Menu* sample_popup =
2212     dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/SamplePopupMenu"));
2213     // update enabled/disabled state of sample popup items
2214     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
2215 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
2216     const int n = rows.size();
2217     int nGroups = 0;
2218     int nSamples = 0;
2219     for (int r = 0; r < n; ++r) {
2220     Gtk::TreeModel::iterator it = m_refSamplesTreeModel->get_iter(rows[r]);
2221     if (!it) continue;
2222 schoenebeck 1225 Gtk::TreeModel::Row row = *it;
2223 schoenebeck 2994 if (row[m_SamplesModel.m_col_group]) nGroups++;
2224     if (row[m_SamplesModel.m_col_sample]) nSamples++;
2225 schoenebeck 1225 }
2226 schoenebeck 2994
2227 schoenebeck 1225 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->
2228 schoenebeck 2994 set_sensitive(n == 1);
2229 schoenebeck 1225 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->
2230 schoenebeck 2994 set_sensitive(n);
2231 schoenebeck 1225 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->
2232     set_sensitive(file);
2233 schoenebeck 2624 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/ShowSampleRefs"))->
2234 schoenebeck 2994 set_sensitive(nSamples == 1);
2235 schoenebeck 1225 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->
2236 schoenebeck 2994 set_sensitive(n);
2237 schoenebeck 1225 // show sample popup
2238     sample_popup->popup(button->button, button->time);
2239 schoenebeck 2625
2240     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuSample/SampleProperties"))->
2241 schoenebeck 2994 set_sensitive(n == 1);
2242 schoenebeck 2625 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuSample/AddSample"))->
2243 schoenebeck 2994 set_sensitive(n);
2244 schoenebeck 2625 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuSample/AddGroup"))->
2245     set_sensitive(file);
2246     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuSample/ShowSampleRefs"))->
2247 schoenebeck 2994 set_sensitive(nSamples == 1);
2248 schoenebeck 2625 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuSample/RemoveSample"))->
2249 schoenebeck 2994 set_sensitive(n);
2250 schoenebeck 1225 }
2251     }
2252    
2253 schoenebeck 2604 void MainWindow::on_script_treeview_button_release(GdkEventButton* button) {
2254     if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
2255     Gtk::Menu* script_popup =
2256     dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/ScriptPopupMenu"));
2257     // update enabled/disabled state of sample popup items
2258     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewScripts.get_selection();
2259     Gtk::TreeModel::iterator it = sel->get_selected();
2260     bool group_selected = false;
2261     bool script_selected = false;
2262     if (it) {
2263     Gtk::TreeModel::Row row = *it;
2264     group_selected = row[m_ScriptsModel.m_col_group];
2265     script_selected = row[m_ScriptsModel.m_col_script];
2266     }
2267     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/ScriptPopupMenu/AddScript"))->
2268     set_sensitive(group_selected || script_selected);
2269     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/ScriptPopupMenu/AddScriptGroup"))->
2270     set_sensitive(file);
2271     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/ScriptPopupMenu/EditScript"))->
2272     set_sensitive(script_selected);
2273     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/ScriptPopupMenu/RemoveScript"))->
2274     set_sensitive(group_selected || script_selected);
2275     // show sample popup
2276     script_popup->popup(button->button, button->time);
2277 schoenebeck 2625
2278     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuScript/AddScript"))->
2279     set_sensitive(group_selected || script_selected);
2280     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuScript/AddScriptGroup"))->
2281     set_sensitive(file);
2282     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuScript/EditScript"))->
2283     set_sensitive(script_selected);
2284     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuScript/RemoveScript"))->
2285     set_sensitive(group_selected || script_selected);
2286 schoenebeck 2604 }
2287     }
2288 persson 2442
2289     Gtk::RadioMenuItem* MainWindow::add_instrument_to_menu(
2290     const Glib::ustring& name, int position) {
2291    
2292     Gtk::RadioMenuItem::Group instrument_group;
2293     const std::vector<Gtk::Widget*> children = instrument_menu->get_children();
2294     if (!children.empty()) {
2295     instrument_group =
2296     static_cast<Gtk::RadioMenuItem*>(children[0])->get_group();
2297     }
2298     Gtk::RadioMenuItem* item =
2299     new Gtk::RadioMenuItem(instrument_group, name);
2300     if (position < 0) {
2301     instrument_menu->append(*item);
2302     } else {
2303     instrument_menu->insert(*item, position);
2304     }
2305     item->show();
2306     item->signal_activate().connect(
2307     sigc::bind(
2308     sigc::mem_fun(*this, &MainWindow::on_instrument_selection_change),
2309     item));
2310     return item;
2311     }
2312    
2313     void MainWindow::remove_instrument_from_menu(int index) {
2314     const std::vector<Gtk::Widget*> children =
2315     instrument_menu->get_children();
2316     Gtk::Widget* child = children[index];
2317     instrument_menu->remove(*child);
2318     delete child;
2319     }
2320    
2321     void MainWindow::add_instrument(gig::Instrument* instrument) {
2322 persson 2446 const Glib::ustring name(gig_to_utf8(instrument->pInfo->Name));
2323 persson 2442
2324     // update instrument tree view
2325     instrument_name_connection.block();
2326     Gtk::TreeModel::iterator iterInstr = m_refTreeModel->append();
2327     Gtk::TreeModel::Row rowInstr = *iterInstr;
2328 schoenebeck 2994 rowInstr[m_Columns.m_col_nr] = m_refTreeModel->children().size() - 1;
2329 persson 2442 rowInstr[m_Columns.m_col_name] = name;
2330     rowInstr[m_Columns.m_col_instr] = instrument;
2331     instrument_name_connection.unblock();
2332    
2333     add_instrument_to_menu(name);
2334    
2335     m_TreeView.get_selection()->select(iterInstr);
2336    
2337     file_changed();
2338     }
2339    
2340 schoenebeck 1225 void MainWindow::on_action_add_instrument() {
2341     static int __instrument_indexer = 0;
2342     if (!file) return;
2343     gig::Instrument* instrument = file->AddInstrument();
2344     __instrument_indexer++;
2345 persson 2446 instrument->pInfo->Name = gig_from_utf8(_("Unnamed Instrument ") +
2346     ToString(__instrument_indexer));
2347 persson 2442
2348     add_instrument(instrument);
2349 schoenebeck 1225 }
2350    
2351 schoenebeck 2395 void MainWindow::on_action_duplicate_instrument() {
2352     if (!file) return;
2353 persson 2442
2354 schoenebeck 2395 // retrieve the currently selected instrument
2355     // (being the original instrument to be duplicated)
2356     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
2357 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
2358     for (int r = 0; r < rows.size(); ++r) {
2359     Gtk::TreeModel::iterator it = m_refTreeModel->get_iter(rows[r]);
2360     if (it) {
2361     Gtk::TreeModel::Row row = *it;
2362     gig::Instrument* instrOrig = row[m_Columns.m_col_instr];
2363     if (instrOrig) {
2364     // duplicate the orginal instrument
2365     gig::Instrument* instrNew = file->AddDuplicateInstrument(instrOrig);
2366     instrNew->pInfo->Name =
2367     instrOrig->pInfo->Name +
2368     gig_from_utf8(Glib::ustring(" (") + _("Copy") + ")");
2369 persson 2442
2370 schoenebeck 2994 add_instrument(instrNew);
2371     }
2372     }
2373     }
2374 schoenebeck 2395 }
2375    
2376 schoenebeck 1225 void MainWindow::on_action_remove_instrument() {
2377     if (!file) return;
2378 schoenebeck 1382 if (file_is_shared) {
2379     Gtk::MessageDialog msg(
2380     *this,
2381     _("You cannot delete an instrument from this file, since it's "
2382     "currently used by the sampler."),
2383     false, Gtk::MESSAGE_INFO
2384     );
2385     msg.run();
2386     return;
2387     }
2388    
2389 schoenebeck 1225 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
2390 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
2391     for (int r = rows.size() - 1; r >= 0; --r) {
2392     Gtk::TreeModel::iterator it = m_refTreeModel->get_iter(rows[r]);
2393     if (!it) continue;
2394 schoenebeck 1225 Gtk::TreeModel::Row row = *it;
2395     gig::Instrument* instr = row[m_Columns.m_col_instr];
2396     try {
2397 persson 2442 Gtk::TreePath path(it);
2398     int index = path[0];
2399    
2400 schoenebeck 1225 // remove instrument from the gig file
2401     if (instr) file->DeleteInstrument(instr);
2402 persson 1261 file_changed();
2403 persson 2423
2404 persson 2442 remove_instrument_from_menu(index);
2405    
2406     // remove row from instruments tree view
2407     m_refTreeModel->erase(it);
2408 schoenebeck 2994 // update "Nr" column of all instrument rows
2409     {
2410     int index = 0;
2411     for (Gtk::TreeModel::iterator it = m_refTreeModel->children().begin();
2412     it != m_refTreeModel->children().end(); ++it, ++index)
2413     {
2414     Gtk::TreeModel::Row row = *it;
2415     row[m_Columns.m_col_nr] = index;
2416     }
2417     }
2418 persson 2442
2419     #if GTKMM_MAJOR_VERSION < 3
2420     // select another instrument (in gtk3 this is done
2421     // automatically)
2422     if (!m_refTreeModel->children().empty()) {
2423     if (index == m_refTreeModel->children().size()) {
2424     index--;
2425     }
2426     m_TreeView.get_selection()->select(
2427     Gtk::TreePath(ToString(index)));
2428     }
2429     #endif
2430 persson 2445 instr_props_set_instrument();
2431 persson 2507 instr = get_instrument();
2432     if (instr) {
2433     midiRules.set_instrument(instr);
2434     } else {
2435     midiRules.hide();
2436     }
2437 schoenebeck 1225 } catch (RIFF::Exception e) {
2438     Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
2439     msg.run();
2440     }
2441     }
2442     }
2443    
2444     void MainWindow::on_action_sample_properties() {
2445     //TODO: show a dialog where the selected sample's properties can be edited
2446     Gtk::MessageDialog msg(
2447 persson 1831 *this, _("Sorry, yet to be implemented!"), false, Gtk::MESSAGE_INFO
2448 schoenebeck 1225 );
2449     msg.run();
2450     }
2451    
2452 schoenebeck 2604 void MainWindow::on_action_add_script_group() {
2453     static int __script_indexer = 0;
2454     if (!file) return;
2455     gig::ScriptGroup* group = file->AddScriptGroup();
2456     group->Name = gig_from_utf8(_("Unnamed Group"));
2457     if (__script_indexer) group->Name += " " + ToString(__script_indexer);
2458     __script_indexer++;
2459     // update sample tree view
2460     Gtk::TreeModel::iterator iterGroup = m_refScriptsTreeModel->append();
2461     Gtk::TreeModel::Row rowGroup = *iterGroup;
2462     rowGroup[m_ScriptsModel.m_col_name] = gig_to_utf8(group->Name);
2463     rowGroup[m_ScriptsModel.m_col_script] = NULL;
2464     rowGroup[m_ScriptsModel.m_col_group] = group;
2465     file_changed();
2466     }
2467    
2468     void MainWindow::on_action_add_script() {
2469     if (!file) return;
2470     // get selected group
2471     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewScripts.get_selection();
2472     Gtk::TreeModel::iterator it = sel->get_selected();
2473     if (!it) return;
2474     Gtk::TreeModel::Row row = *it;
2475     gig::ScriptGroup* group = row[m_ScriptsModel.m_col_group];
2476     if (!group) { // not a group, but a script is selected (probably)
2477     gig::Script* script = row[m_ScriptsModel.m_col_script];
2478     if (!script) return;
2479     it = row.parent(); // resolve parent (that is the script's group)
2480     if (!it) return;
2481     row = *it;
2482     group = row[m_ScriptsModel.m_col_group];
2483     if (!group) return;
2484     }
2485    
2486     // add a new script to the .gig file
2487     gig::Script* script = group->AddScript();
2488     Glib::ustring name = _("Unnamed Script");
2489     script->Name = gig_from_utf8(name);
2490    
2491     // add script to the tree view
2492     Gtk::TreeModel::iterator iterScript =
2493     m_refScriptsTreeModel->append(row.children());
2494     Gtk::TreeModel::Row rowScript = *iterScript;
2495     rowScript[m_ScriptsModel.m_col_name] = name;
2496     rowScript[m_ScriptsModel.m_col_script] = script;
2497     rowScript[m_ScriptsModel.m_col_group] = NULL;
2498    
2499     // unfold group of new script item in treeview
2500     Gtk::TreeModel::Path path(iterScript);
2501     m_TreeViewScripts.expand_to_path(path);
2502     }
2503    
2504     void MainWindow::on_action_edit_script() {
2505     if (!file) return;
2506     // get selected script
2507     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewScripts.get_selection();
2508     Gtk::TreeModel::iterator it = sel->get_selected();
2509     if (!it) return;
2510     Gtk::TreeModel::Row row = *it;
2511     gig::Script* script = row[m_ScriptsModel.m_col_script];
2512     if (!script) return;
2513    
2514     ScriptEditor* editor = new ScriptEditor;
2515 schoenebeck 2903 editor->signal_script_to_be_changed.connect(
2516     signal_script_to_be_changed.make_slot()
2517     );
2518     editor->signal_script_changed.connect(
2519     signal_script_changed.make_slot()
2520     );
2521 schoenebeck 2604 editor->setScript(script);
2522     //editor->reparent(*this);
2523     editor->show();
2524     }
2525    
2526     void MainWindow::on_action_remove_script() {
2527     if (!file) return;
2528     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewScripts.get_selection();
2529     Gtk::TreeModel::iterator it = sel->get_selected();
2530     if (it) {
2531     Gtk::TreeModel::Row row = *it;
2532     gig::ScriptGroup* group = row[m_ScriptsModel.m_col_group];
2533     gig::Script* script = row[m_ScriptsModel.m_col_script];
2534     Glib::ustring name = row[m_ScriptsModel.m_col_name];
2535     try {
2536     // remove script group or script from the gig file
2537     if (group) {
2538     // notify everybody that we're going to remove these samples
2539     //TODO: scripts_to_be_removed_signal.emit(members);
2540     // delete the group in the .gig file including the
2541     // samples that belong to the group
2542     file->DeleteScriptGroup(group);
2543     // notify that we're done with removal
2544     //TODO: scripts_removed_signal.emit();
2545     file_changed();
2546     } else if (script) {
2547     // notify everybody that we're going to remove this sample
2548     //TODO: std::list<gig::Script*> lscripts;
2549     //TODO: lscripts.push_back(script);
2550     //TODO: scripts_to_be_removed_signal.emit(lscripts);
2551     // remove sample from the .gig file
2552     script->GetGroup()->DeleteScript(script);
2553     // notify that we're done with removal
2554     //TODO: scripts_removed_signal.emit();
2555     dimreg_changed();
2556     file_changed();
2557     }
2558     // remove respective row(s) from samples tree view
2559     m_refScriptsTreeModel->erase(it);
2560     } catch (RIFF::Exception e) {
2561     // pretend we're done with removal (i.e. to avoid dead locks)
2562     //TODO: scripts_removed_signal.emit();
2563     // show error message
2564     Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
2565     msg.run();
2566     }
2567     }
2568     }
2569    
2570 schoenebeck 1225 void MainWindow::on_action_add_group() {
2571     static int __sample_indexer = 0;
2572     if (!file) return;
2573     gig::Group* group = file->AddGroup();
2574 persson 2446 group->Name = gig_from_utf8(_("Unnamed Group"));
2575 schoenebeck 1225 if (__sample_indexer) group->Name += " " + ToString(__sample_indexer);
2576     __sample_indexer++;
2577     // update sample tree view
2578     Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
2579     Gtk::TreeModel::Row rowGroup = *iterGroup;
2580 persson 2446 rowGroup[m_SamplesModel.m_col_name] = gig_to_utf8(group->Name);
2581 schoenebeck 1225 rowGroup[m_SamplesModel.m_col_sample] = NULL;
2582     rowGroup[m_SamplesModel.m_col_group] = group;
2583 persson 1261 file_changed();
2584 schoenebeck 1225 }
2585    
2586 schoenebeck 2715 void MainWindow::on_action_replace_sample() {
2587     add_or_replace_sample(true);
2588     }
2589    
2590 schoenebeck 1225 void MainWindow::on_action_add_sample() {
2591 schoenebeck 2715 add_or_replace_sample(false);
2592     }
2593    
2594     void MainWindow::add_or_replace_sample(bool replace) {
2595 schoenebeck 1225 if (!file) return;
2596 schoenebeck 2715
2597     // get selected group (and probably selected sample)
2598 schoenebeck 1225 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
2599 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
2600     if (rows.empty()) return;
2601     Gtk::TreeModel::iterator it = m_refSamplesTreeModel->get_iter(rows[0]);
2602 schoenebeck 1225 if (!it) return;
2603     Gtk::TreeModel::Row row = *it;
2604 schoenebeck 2715 gig::Sample* sample = NULL;
2605 schoenebeck 1225 gig::Group* group = row[m_SamplesModel.m_col_group];
2606     if (!group) { // not a group, but a sample is selected (probably)
2607 schoenebeck 2715 if (replace) sample = row[m_SamplesModel.m_col_sample];
2608     if (!row[m_SamplesModel.m_col_sample]) return;
2609 schoenebeck 1225 it = row.parent(); // resolve parent (that is the sample's group)
2610     if (!it) return;
2611 schoenebeck 2715 if (!replace) row = *it;
2612     group = (*it)[m_SamplesModel.m_col_group];
2613 schoenebeck 1225 if (!group) return;
2614     }
2615 schoenebeck 2715 if (replace && !sample) return;
2616    
2617 schoenebeck 1225 // show 'browse for file' dialog
2618 schoenebeck 2715 Gtk::FileChooserDialog dialog(*this, replace ? _("Replace Sample with") : _("Add Sample(s)"));
2619 persson 2845 dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
2620     dialog.add_button(_("_Open"), Gtk::RESPONSE_OK);
2621 schoenebeck 2715 dialog.set_select_multiple(!replace); // allow multi audio file selection only when adding new samples, does not make sense when replacing a specific sample
2622 persson 2169
2623     // matches all file types supported by libsndfile
2624     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
2625     Gtk::FileFilter soundfilter;
2626     #else
2627     Glib::RefPtr<Gtk::FileFilter> soundfilter = Gtk::FileFilter::create();
2628     #endif
2629 persson 1262 const char* const supportedFileTypes[] = {
2630 schoenebeck 1225 "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
2631     "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
2632     "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
2633     "*.W64", "*.pvf", "*.PVF", "*.xi", "*.XI", "*.htk", "*.HTK",
2634     "*.caf", "*.CAF", NULL
2635     };
2636 persson 2169 const char* soundfiles = _("Sound Files");
2637     const char* allfiles = _("All Files");
2638     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
2639 schoenebeck 1225 for (int i = 0; supportedFileTypes[i]; i++)
2640     soundfilter.add_pattern(supportedFileTypes[i]);
2641 persson 2169 soundfilter.set_name(soundfiles);
2642    
2643     // matches every file
2644     Gtk::FileFilter allpassfilter;
2645 schoenebeck 1225 allpassfilter.add_pattern("*.*");
2646 persson 2169 allpassfilter.set_name(allfiles);
2647     #else
2648     for (int i = 0; supportedFileTypes[i]; i++)
2649     soundfilter->add_pattern(supportedFileTypes[i]);
2650     soundfilter->set_name(soundfiles);
2651    
2652     // matches every file
2653     Glib::RefPtr<Gtk::FileFilter> allpassfilter = Gtk::FileFilter::create();
2654     allpassfilter->add_pattern("*.*");
2655     allpassfilter->set_name(allfiles);
2656     #endif
2657 schoenebeck 1225 dialog.add_filter(soundfilter);
2658     dialog.add_filter(allpassfilter);
2659 persson 1725 if (current_sample_dir != "") {
2660     dialog.set_current_folder(current_sample_dir);
2661     }
2662 schoenebeck 1225 if (dialog.run() == Gtk::RESPONSE_OK) {
2663 persson 1725 current_sample_dir = dialog.get_current_folder();
2664 schoenebeck 1225 Glib::ustring error_files;
2665 persson 2169 std::vector<std::string> filenames = dialog.get_filenames();
2666     for (std::vector<std::string>::iterator iter = filenames.begin();
2667 schoenebeck 1225 iter != filenames.end(); ++iter) {
2668     printf("Adding sample %s\n",(*iter).c_str());
2669     // use libsndfile to retrieve file informations
2670     SF_INFO info;
2671     info.format = 0;
2672     SNDFILE* hFile = sf_open((*iter).c_str(), SFM_READ, &info);
2673     try {
2674 persson 1831 if (!hFile) throw std::string(_("could not open file"));
2675 schoenebeck 1225 int bitdepth;
2676     switch (info.format & 0xff) {
2677     case SF_FORMAT_PCM_S8:
2678     case SF_FORMAT_PCM_16:
2679 persson 1265 case SF_FORMAT_PCM_U8:
2680 schoenebeck 1225 bitdepth = 16;
2681     break;
2682     case SF_FORMAT_PCM_24:
2683     case SF_FORMAT_PCM_32:
2684     case SF_FORMAT_FLOAT:
2685     case SF_FORMAT_DOUBLE:
2686 persson 1265 bitdepth = 24;
2687 schoenebeck 1225 break;
2688     default:
2689     sf_close(hFile); // close sound file
2690 persson 1831 throw std::string(_("format not supported")); // unsupported subformat (yet?)
2691 schoenebeck 1225 }
2692 schoenebeck 2715 // add a new sample to the .gig file (if adding is requested actually)
2693     if (!replace) sample = file->AddSample();
2694 schoenebeck 1225 // file name without path
2695 persson 1262 Glib::ustring filename = Glib::filename_display_basename(*iter);
2696     // remove file extension if there is one
2697     for (int i = 0; supportedFileTypes[i]; i++) {
2698     if (Glib::str_has_suffix(filename, supportedFileTypes[i] + 1)) {
2699     filename.erase(filename.length() - strlen(supportedFileTypes[i] + 1));
2700     break;
2701     }
2702     }
2703 persson 2446 sample->pInfo->Name = gig_from_utf8(filename);
2704 schoenebeck 1225 sample->Channels = info.channels;
2705     sample->BitDepth = bitdepth;
2706     sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
2707     sample->SamplesPerSecond = info.samplerate;
2708 persson 1265 sample->AverageBytesPerSecond = sample->FrameSize * sample->SamplesPerSecond;
2709     sample->BlockAlign = sample->FrameSize;
2710     sample->SamplesTotal = info.frames;
2711    
2712     SF_INSTRUMENT instrument;
2713     if (sf_command(hFile, SFC_GET_INSTRUMENT,
2714     &instrument, sizeof(instrument)) != SF_FALSE)
2715     {
2716     sample->MIDIUnityNote = instrument.basenote;
2717 schoenebeck 2466 sample->FineTune = instrument.detune;
2718 persson 1265
2719     if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
2720     sample->Loops = 1;
2721    
2722     switch (instrument.loops[0].mode) {
2723     case SF_LOOP_FORWARD:
2724     sample->LoopType = gig::loop_type_normal;
2725     break;
2726     case SF_LOOP_BACKWARD:
2727     sample->LoopType = gig::loop_type_backward;
2728     break;
2729     case SF_LOOP_ALTERNATING:
2730     sample->LoopType = gig::loop_type_bidirectional;
2731     break;
2732     }
2733     sample->LoopStart = instrument.loops[0].start;
2734     sample->LoopEnd = instrument.loops[0].end;
2735     sample->LoopPlayCount = instrument.loops[0].count;
2736     sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
2737     }
2738     }
2739    
2740 schoenebeck 1225 // schedule resizing the sample (which will be done
2741     // physically when File::Save() is called)
2742     sample->Resize(info.frames);
2743     // make sure sample is part of the selected group
2744 schoenebeck 2715 if (!replace) group->AddSample(sample);
2745 schoenebeck 1225 // schedule that physical resize and sample import
2746     // (data copying), performed when "Save" is requested
2747     SampleImportItem sched_item;
2748     sched_item.gig_sample = sample;
2749     sched_item.sample_path = *iter;
2750     m_SampleImportQueue.push_back(sched_item);
2751     // add sample to the tree view
2752 schoenebeck 2715 if (replace) {
2753     row[m_SamplesModel.m_col_name] = gig_to_utf8(sample->pInfo->Name);
2754     } else {
2755     Gtk::TreeModel::iterator iterSample =
2756     m_refSamplesTreeModel->append(row.children());
2757     Gtk::TreeModel::Row rowSample = *iterSample;
2758     rowSample[m_SamplesModel.m_col_name] =
2759     gig_to_utf8(sample->pInfo->Name);
2760     rowSample[m_SamplesModel.m_col_sample] = sample;
2761     rowSample[m_SamplesModel.m_col_group] = NULL;
2762     }
2763 schoenebeck 1225 // close sound file
2764     sf_close(hFile);
2765 persson 1261 file_changed();
2766 schoenebeck 1225 } catch (std::string what) { // remember the files that made trouble (and their cause)
2767 persson 2442 if (!error_files.empty()) error_files += "\n";
2768 schoenebeck 1225 error_files += *iter += " (" + what + ")";
2769     }
2770     }
2771     // show error message box when some file(s) could not be opened / added
2772 persson 2442 if (!error_files.empty()) {
2773 schoenebeck 2715 Glib::ustring txt =
2774     (replace
2775     ? _("Failed to replace sample with:\n")
2776     : _("Could not add the following sample(s):\n"))
2777     + error_files;
2778 schoenebeck 1225 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
2779     msg.run();
2780     }
2781     }
2782     }
2783    
2784 schoenebeck 1673 void MainWindow::on_action_replace_all_samples_in_all_groups()
2785     {
2786     if (!file) return;
2787     Gtk::FileChooserDialog dialog(*this, _("Select Folder"),
2788     Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
2789 persson 2442 const char* str =
2790 schoenebeck 1673 _("This is a very specific function. It tries to replace all samples "
2791 persson 1799 "in the current gig file by samples located in the chosen "
2792     "directory.\n\n"
2793     "It works like this: For each sample in the gig file, it tries to "
2794 schoenebeck 1673 "find a sample file in the selected directory with the same name as "
2795 persson 1799 "the sample in the gig file. Optionally, you can add a filename "
2796     "extension below, which will be added to the filename expected to be "
2797 schoenebeck 1673 "found. That is, assume you have a gig file with a sample called "
2798     "'Snare', if you enter '.wav' below (like it's done by default), it "
2799 persson 1799 "expects to find a sample file called 'Snare.wav' and will replace "
2800     "the sample in the gig file accordingly. If you don't need an "
2801     "extension, blank the field below. Any gig sample where no "
2802     "appropriate sample file could be found will be reported and left "
2803 persson 2344 "untouched.\n");
2804     #if GTKMM_MAJOR_VERSION < 3
2805     view::WrapLabel description(str);
2806     #else
2807     Gtk::Label description(str);
2808     description.set_line_wrap();
2809     #endif
2810 schoenebeck 1673 Gtk::HBox entryArea;
2811 persson 2169 Gtk::Label entryLabel( _("Add filename extension: "), Gtk::ALIGN_START);
2812 schoenebeck 1673 Gtk::Entry postfixEntryBox;
2813     postfixEntryBox.set_text(".wav");
2814     entryArea.pack_start(entryLabel);
2815     entryArea.pack_start(postfixEntryBox);
2816     dialog.get_vbox()->pack_start(description, Gtk::PACK_SHRINK);
2817     dialog.get_vbox()->pack_start(entryArea, Gtk::PACK_SHRINK);
2818     description.show();
2819 persson 1799 entryArea.show_all();
2820 persson 2845 dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
2821 schoenebeck 1673 dialog.add_button(_("Select"), Gtk::RESPONSE_OK);
2822     dialog.set_select_multiple(false);
2823 persson 1725 if (current_sample_dir != "") {
2824     dialog.set_current_folder(current_sample_dir);
2825     }
2826 schoenebeck 1673 if (dialog.run() == Gtk::RESPONSE_OK)
2827     {
2828 persson 1725 current_sample_dir = dialog.get_current_folder();
2829 schoenebeck 1673 Glib::ustring error_files;
2830 persson 2169 std::string folder = dialog.get_filename();
2831 schoenebeck 1673 for (gig::Sample* sample = file->GetFirstSample();
2832     sample; sample = file->GetNextSample())
2833     {
2834     std::string filename =
2835 persson 2446 folder + G_DIR_SEPARATOR_S +
2836     Glib::filename_from_utf8(gig_to_utf8(sample->pInfo->Name) +
2837     postfixEntryBox.get_text());
2838 schoenebeck 1673 SF_INFO info;
2839     info.format = 0;
2840     SNDFILE* hFile = sf_open(filename.c_str(), SFM_READ, &info);
2841     try
2842     {
2843 persson 1831 if (!hFile) throw std::string(_("could not open file"));
2844 schoenebeck 1673 switch (info.format & 0xff) {
2845     case SF_FORMAT_PCM_S8:
2846     case SF_FORMAT_PCM_16:
2847     case SF_FORMAT_PCM_U8:
2848     case SF_FORMAT_PCM_24:
2849     case SF_FORMAT_PCM_32:
2850     case SF_FORMAT_FLOAT:
2851     case SF_FORMAT_DOUBLE:
2852     break;
2853     default:
2854     sf_close(hFile);
2855 persson 1831 throw std::string(_("format not supported"));
2856 schoenebeck 1673 }
2857     SampleImportItem sched_item;
2858     sched_item.gig_sample = sample;
2859     sched_item.sample_path = filename;
2860     m_SampleImportQueue.push_back(sched_item);
2861     sf_close(hFile);
2862     file_changed();
2863     }
2864     catch (std::string what)
2865     {
2866 persson 2442 if (!error_files.empty()) error_files += "\n";
2867 persson 2446 error_files += Glib::filename_to_utf8(filename) +
2868     " (" + what + ")";
2869 schoenebeck 1673 }
2870     }
2871     // show error message box when some file(s) could not be opened / added
2872 persson 2442 if (!error_files.empty()) {
2873 schoenebeck 1673 Glib::ustring txt =
2874     _("Could not replace the following sample(s):\n") + error_files;
2875     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
2876     msg.run();
2877     }
2878     }
2879     }
2880    
2881 schoenebeck 1225 void MainWindow::on_action_remove_sample() {
2882     if (!file) return;
2883     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
2884 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
2885     for (int r = rows.size() - 1; r >= 0; --r) {
2886     Gtk::TreeModel::iterator it = m_refSamplesTreeModel->get_iter(rows[r]);
2887     if (!it) continue;
2888 schoenebeck 1225 Gtk::TreeModel::Row row = *it;
2889     gig::Group* group = row[m_SamplesModel.m_col_group];
2890     gig::Sample* sample = row[m_SamplesModel.m_col_sample];
2891     Glib::ustring name = row[m_SamplesModel.m_col_name];
2892     try {
2893     // remove group or sample from the gig file
2894     if (group) {
2895 persson 2446 // temporarily remember the samples that belong to
2896 schoenebeck 1225 // that group (we need that to clean the queue)
2897     std::list<gig::Sample*> members;
2898     for (gig::Sample* pSample = group->GetFirstSample();
2899     pSample; pSample = group->GetNextSample()) {
2900     members.push_back(pSample);
2901     }
2902 schoenebeck 1322 // notify everybody that we're going to remove these samples
2903     samples_to_be_removed_signal.emit(members);
2904 schoenebeck 1225 // delete the group in the .gig file including the
2905     // samples that belong to the group
2906     file->DeleteGroup(group);
2907 schoenebeck 1322 // notify that we're done with removal
2908     samples_removed_signal.emit();
2909 schoenebeck 1225 // if sample(s) were just previously added, remove
2910     // them from the import queue
2911     for (std::list<gig::Sample*>::iterator member = members.begin();
2912     member != members.end(); ++member) {
2913     for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
2914     iter != m_SampleImportQueue.end(); ++iter) {
2915     if ((*iter).gig_sample == *member) {
2916     printf("Removing previously added sample '%s' from group '%s'\n",
2917     (*iter).sample_path.c_str(), name.c_str());
2918     m_SampleImportQueue.erase(iter);
2919     break;
2920     }
2921     }
2922     }
2923 persson 1261 file_changed();
2924 schoenebeck 1225 } else if (sample) {
2925 schoenebeck 1322 // notify everybody that we're going to remove this sample
2926     std::list<gig::Sample*> lsamples;
2927     lsamples.push_back(sample);
2928     samples_to_be_removed_signal.emit(lsamples);
2929 schoenebeck 1225 // remove sample from the .gig file
2930     file->DeleteSample(sample);
2931 schoenebeck 1322 // notify that we're done with removal
2932     samples_removed_signal.emit();
2933 schoenebeck 1225 // if sample was just previously added, remove it from
2934     // the import queue
2935     for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
2936     iter != m_SampleImportQueue.end(); ++iter) {
2937     if ((*iter).gig_sample == sample) {
2938     printf("Removing previously added sample '%s'\n",
2939     (*iter).sample_path.c_str());
2940     m_SampleImportQueue.erase(iter);
2941     break;
2942     }
2943     }
2944 persson 1303 dimreg_changed();
2945 persson 1261 file_changed();
2946 schoenebeck 1225 }
2947     // remove respective row(s) from samples tree view
2948     m_refSamplesTreeModel->erase(it);
2949     } catch (RIFF::Exception e) {
2950 schoenebeck 1322 // pretend we're done with removal (i.e. to avoid dead locks)
2951     samples_removed_signal.emit();
2952     // show error message
2953 schoenebeck 1225 Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
2954     msg.run();
2955     }
2956     }
2957     }
2958    
2959 schoenebeck 2772 void MainWindow::on_action_remove_unused_samples() {
2960     if (!file) return;
2961    
2962     // collect all samples that are not referenced by any instrument
2963     std::list<gig::Sample*> lsamples;
2964     for (int iSample = 0; file->GetSample(iSample); ++iSample) {
2965     gig::Sample* sample = file->GetSample(iSample);
2966     bool isUsed = false;
2967     for (gig::Instrument* instrument = file->GetFirstInstrument(); instrument;
2968     instrument = file->GetNextInstrument())
2969     {
2970     for (gig::Region* rgn = instrument->GetFirstRegion(); rgn;
2971     rgn = instrument->GetNextRegion())
2972     {
2973     for (int i = 0; i < 256; ++i) {
2974     if (!rgn->pDimensionRegions[i]) continue;
2975     if (rgn->pDimensionRegions[i]->pSample != sample) continue;
2976     isUsed = true;
2977     goto endOfRefSearch;
2978     }
2979     }
2980     }
2981     endOfRefSearch:
2982     if (!isUsed) lsamples.push_back(sample);
2983     }
2984    
2985     if (lsamples.empty()) return;
2986    
2987     // notify everybody that we're going to remove these samples
2988     samples_to_be_removed_signal.emit(lsamples);
2989    
2990     // remove collected samples
2991     try {
2992     for (std::list<gig::Sample*>::iterator itSample = lsamples.begin();
2993     itSample != lsamples.end(); ++itSample)
2994     {
2995     gig::Sample* sample = *itSample;
2996     // remove sample from the .gig file
2997     file->DeleteSample(sample);
2998     // if sample was just previously added, remove it fro the import queue
2999     for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
3000     iter != m_SampleImportQueue.end(); ++iter)
3001     {
3002     if ((*iter).gig_sample == sample) {
3003     printf("Removing previously added sample '%s'\n",
3004     (*iter).sample_path.c_str());
3005     m_SampleImportQueue.erase(iter);
3006     break;
3007     }
3008     }
3009     }
3010     } catch (RIFF::Exception e) {
3011     // show error message
3012     Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
3013     msg.run();
3014     }
3015    
3016     // notify everybody that we're done with removal
3017     samples_removed_signal.emit();
3018    
3019     dimreg_changed();
3020     file_changed();
3021     __refreshEntireGUI();
3022     }
3023    
3024 schoenebeck 2610 // see comment on on_sample_treeview_drag_begin()
3025     void MainWindow::on_scripts_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
3026     {
3027     first_call_to_drag_data_get = true;
3028     }
3029    
3030     void MainWindow::on_scripts_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,
3031     Gtk::SelectionData& selection_data, guint, guint)
3032     {
3033     if (!first_call_to_drag_data_get) return;
3034     first_call_to_drag_data_get = false;
3035    
3036     // get selected script
3037     gig::Script* script = NULL;
3038     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewScripts.get_selection();
3039     Gtk::TreeModel::iterator it = sel->get_selected();
3040     if (it) {
3041     Gtk::TreeModel::Row row = *it;
3042     script = row[m_ScriptsModel.m_col_script];
3043     }
3044     // pass the gig::Script as pointer
3045     selection_data.set(selection_data.get_target(), 0/*unused*/,
3046     (const guchar*)&script,
3047     sizeof(script)/*length of data in bytes*/);
3048     }
3049    
3050 schoenebeck 2701 // see comment on on_sample_treeview_drag_begin()
3051     void MainWindow::on_instruments_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
3052     {
3053     first_call_to_drag_data_get = true;
3054     }
3055    
3056     void MainWindow::on_instruments_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,
3057     Gtk::SelectionData& selection_data, guint, guint)
3058     {
3059     if (!first_call_to_drag_data_get) return;
3060     first_call_to_drag_data_get = false;
3061    
3062     // get selected source instrument
3063     gig::Instrument* src = NULL;
3064     {
3065     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
3066 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
3067     if (!rows.empty()) {
3068     Gtk::TreeModel::iterator it = m_refTreeModel->get_iter(rows[0]);
3069     if (it) {
3070     Gtk::TreeModel::Row row = *it;
3071     src = row[m_Columns.m_col_instr];
3072     }
3073 schoenebeck 2701 }
3074     }
3075     if (!src) return;
3076    
3077     // pass the source gig::Instrument as pointer
3078     selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&src,
3079     sizeof(src)/*length of data in bytes*/);
3080     }
3081    
3082     void MainWindow::on_instruments_treeview_drop_drag_data_received(
3083     const Glib::RefPtr<Gdk::DragContext>& context, int x, int y,
3084     const Gtk::SelectionData& selection_data, guint, guint time)
3085     {
3086     gig::Instrument* src = *((gig::Instrument**) selection_data.get_data());
3087     if (!src || selection_data.get_length() != sizeof(gig::Instrument*))
3088     return;
3089    
3090     gig::Instrument* dst = NULL;
3091     {
3092     Gtk::TreeModel::Path path;
3093     const bool found = m_TreeView.get_path_at_pos(x, y, path);
3094     if (!found) return;
3095    
3096     Gtk::TreeModel::iterator iter = m_refTreeModel->get_iter(path);
3097     if (!iter) return;
3098     Gtk::TreeModel::Row row = *iter;
3099     dst = row[m_Columns.m_col_instr];
3100     }
3101     if (!dst) return;
3102    
3103     //printf("dragdrop received src=%s dst=%s\n", src->pInfo->Name.c_str(), dst->pInfo->Name.c_str());
3104     src->MoveTo(dst);
3105     __refreshEntireGUI();
3106     select_instrument(src);
3107     }
3108    
3109 persson 1303 // For some reason drag_data_get gets called two times for each
3110     // drag'n'drop (at least when target is an Entry). This work-around
3111     // makes sure the code in drag_data_get and drop_drag_data_received is
3112     // only executed once, as drag_begin only gets called once.
3113     void MainWindow::on_sample_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
3114     {
3115     first_call_to_drag_data_get = true;
3116     }
3117    
3118 schoenebeck 1225 void MainWindow::on_sample_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,
3119     Gtk::SelectionData& selection_data, guint, guint)
3120     {
3121 persson 1303 if (!first_call_to_drag_data_get) return;
3122     first_call_to_drag_data_get = false;
3123    
3124 schoenebeck 1225 // get selected sample
3125     gig::Sample* sample = NULL;
3126     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
3127 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
3128     if (!rows.empty()) {
3129     Gtk::TreeModel::iterator it = m_refSamplesTreeModel->get_iter(rows[0]);
3130     if (it) {
3131     Gtk::TreeModel::Row row = *it;
3132     sample = row[m_SamplesModel.m_col_sample];
3133     }
3134 schoenebeck 1225 }
3135     // pass the gig::Sample as pointer
3136     selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&sample,
3137     sizeof(sample)/*length of data in bytes*/);
3138     }
3139    
3140     void MainWindow::on_sample_label_drop_drag_data_received(
3141     const Glib::RefPtr<Gdk::DragContext>& context, int, int,
3142     const Gtk::SelectionData& selection_data, guint, guint time)
3143     {
3144     gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
3145    
3146 persson 1265 if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
3147 persson 1303 std::cout << "Drop received sample \"" <<
3148     sample->pInfo->Name << "\"" << std::endl;
3149     // drop success
3150     context->drop_reply(true, time);
3151    
3152 schoenebeck 1322 //TODO: we should better move most of the following code to DimRegionEdit::set_sample()
3153    
3154     // notify everybody that we're going to alter the region
3155     gig::Region* region = m_RegionChooser.get_region();
3156     region_to_be_changed_signal.emit(region);
3157    
3158 persson 1303 // find the samplechannel dimension
3159     gig::dimension_def_t* stereo_dimension = 0;
3160     for (int i = 0 ; i < region->Dimensions ; i++) {
3161     if (region->pDimensionDefinitions[i].dimension ==
3162     gig::dimension_samplechannel) {
3163     stereo_dimension = &region->pDimensionDefinitions[i];
3164     break;
3165     }
3166 schoenebeck 1225 }
3167 persson 1303 bool channels_changed = false;
3168     if (sample->Channels == 1 && stereo_dimension) {
3169     // remove the samplechannel dimension
3170 schoenebeck 2550 /* commented out, because it makes it impossible building up an instrument from scratch using two separate L/R samples
3171 persson 1303 region->DeleteDimension(stereo_dimension);
3172     channels_changed = true;
3173     region_changed();
3174 schoenebeck 2550 */
3175 persson 1303 }
3176 schoenebeck 2464 dimreg_edit.set_sample(
3177     sample,
3178     is_copy_samples_unity_note_enabled(),
3179     is_copy_samples_fine_tune_enabled(),
3180     is_copy_samples_loop_enabled()
3181     );
3182 persson 1303
3183     if (sample->Channels == 2 && !stereo_dimension) {
3184     // add samplechannel dimension
3185     gig::dimension_def_t dim;
3186     dim.dimension = gig::dimension_samplechannel;
3187     dim.bits = 1;
3188     dim.zones = 2;
3189     region->AddDimension(&dim);
3190     channels_changed = true;
3191     region_changed();
3192     }
3193     if (channels_changed) {
3194     // unmap all samples with wrong number of channels
3195     // TODO: maybe there should be a warning dialog for this
3196     for (int i = 0 ; i < region->DimensionRegions ; i++) {
3197     gig::DimensionRegion* d = region->pDimensionRegions[i];
3198     if (d->pSample && d->pSample->Channels != sample->Channels) {
3199 schoenebeck 1322 gig::Sample* oldref = d->pSample;
3200     d->pSample = NULL;
3201     sample_ref_changed_signal.emit(oldref, NULL);
3202 persson 1303 }
3203     }
3204     }
3205    
3206 schoenebeck 1322 // notify we're done with altering
3207     region_changed_signal.emit(region);
3208    
3209 persson 1460 file_changed();
3210    
3211 persson 1303 return;
3212 schoenebeck 1225 }
3213     // drop failed
3214     context->drop_reply(false, time);
3215     }
3216    
3217     void MainWindow::sample_name_changed(const Gtk::TreeModel::Path& path,
3218     const Gtk::TreeModel::iterator& iter) {
3219     if (!iter) return;
3220     Gtk::TreeModel::Row row = *iter;
3221     Glib::ustring name = row[m_SamplesModel.m_col_name];
3222     gig::Group* group = row[m_SamplesModel.m_col_group];
3223     gig::Sample* sample = row[m_SamplesModel.m_col_sample];
3224 persson 2446 gig::String gigname(gig_from_utf8(name));
3225 schoenebeck 1225 if (group) {
3226 persson 2446 if (group->Name != gigname) {
3227     group->Name = gigname;
3228 persson 1261 printf("group name changed\n");
3229     file_changed();
3230     }
3231 schoenebeck 1225 } else if (sample) {
3232 persson 2446 if (sample->pInfo->Name != gigname) {
3233     sample->pInfo->Name = gigname;
3234 persson 1261 printf("sample name changed\n");
3235     file_changed();
3236     }
3237 schoenebeck 1225 }
3238     }
3239    
3240 schoenebeck 2604 void MainWindow::script_name_changed(const Gtk::TreeModel::Path& path,
3241     const Gtk::TreeModel::iterator& iter) {
3242     if (!iter) return;
3243     Gtk::TreeModel::Row row = *iter;
3244     Glib::ustring name = row[m_ScriptsModel.m_col_name];
3245     gig::ScriptGroup* group = row[m_ScriptsModel.m_col_group];
3246     gig::Script* script = row[m_ScriptsModel.m_col_script];
3247     gig::String gigname(gig_from_utf8(name));
3248     if (group) {
3249     if (group->Name != gigname) {
3250     group->Name = gigname;
3251     printf("script group name changed\n");
3252     file_changed();
3253     }
3254     } else if (script) {
3255     if (script->Name != gigname) {
3256     script->Name = gigname;
3257     printf("script name changed\n");
3258     file_changed();
3259     }
3260     }
3261     }
3262    
3263 schoenebeck 2644 void MainWindow::script_double_clicked(const Gtk::TreeModel::Path& path,
3264     Gtk::TreeViewColumn* column)
3265     {
3266     Gtk::TreeModel::iterator iter = m_refScriptsTreeModel->get_iter(path);
3267     if (!iter) return;
3268     Gtk::TreeModel::Row row = *iter;
3269     gig::Script* script = row[m_ScriptsModel.m_col_script];
3270     if (!script) return;
3271    
3272     ScriptEditor* editor = new ScriptEditor;
3273 schoenebeck 2903 editor->signal_script_to_be_changed.connect(
3274     signal_script_to_be_changed.make_slot()
3275     );
3276     editor->signal_script_changed.connect(
3277     signal_script_changed.make_slot()
3278     );
3279 schoenebeck 2644 editor->setScript(script);
3280     //editor->reparent(*this);
3281     editor->show();
3282     }
3283    
3284 schoenebeck 1225 void MainWindow::instrument_name_changed(const Gtk::TreeModel::Path& path,
3285     const Gtk::TreeModel::iterator& iter) {
3286     if (!iter) return;
3287     Gtk::TreeModel::Row row = *iter;
3288     Glib::ustring name = row[m_Columns.m_col_name];
3289 persson 2442
3290     // change name in instrument menu
3291     int index = path[0];
3292     const std::vector<Gtk::Widget*> children = instrument_menu->get_children();
3293     if (index < children.size()) {
3294     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 16) || GTKMM_MAJOR_VERSION > 2
3295     static_cast<Gtk::RadioMenuItem*>(children[index])->set_label(name);
3296     #else
3297     remove_instrument_from_menu(index);
3298     Gtk::RadioMenuItem* item = add_instrument_to_menu(name, index);
3299     item->set_active();
3300     #endif
3301     }
3302    
3303     // change name in gig
3304 schoenebeck 1225 gig::Instrument* instrument = row[m_Columns.m_col_instr];
3305 persson 2446 gig::String gigname(gig_from_utf8(name));
3306     if (instrument && instrument->pInfo->Name != gigname) {
3307     instrument->pInfo->Name = gigname;
3308 persson 2445
3309     // change name in the instrument properties window
3310     if (instrumentProps.get_instrument() == instrument) {
3311     instrumentProps.update_name();
3312     }
3313    
3314 persson 1261 file_changed();
3315     }
3316 schoenebeck 1225 }
3317 schoenebeck 1322
3318 schoenebeck 2548 void MainWindow::on_action_combine_instruments() {
3319     CombineInstrumentsDialog* d = new CombineInstrumentsDialog(*this, file);
3320     d->show_all();
3321     d->resize(500, 400);
3322     d->run();
3323     if (d->fileWasChanged()) {
3324     // update GUI with new instrument just created
3325     add_instrument(d->newCombinedInstrument());
3326     }
3327     delete d;
3328     }
3329    
3330 schoenebeck 2624 void MainWindow::on_action_view_references() {
3331     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
3332 schoenebeck 2994 std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
3333     if (rows.empty()) return;
3334     Gtk::TreeModel::iterator it = m_refSamplesTreeModel->get_iter(rows[0]);
3335 schoenebeck 2624 if (!it) return;
3336     Gtk::TreeModel::Row row = *it;
3337     gig::Sample* sample = row[m_SamplesModel.m_col_sample];
3338     if (!sample) return;
3339    
3340     ReferencesView* d = new ReferencesView(*this);
3341     d->setSample(sample);
3342 schoenebeck 2695 d->dimension_region_selected.connect(
3343     sigc::mem_fun(*this, &MainWindow::select_dimension_region)
3344     );
3345 schoenebeck 2624 d->show_all();
3346     d->resize(500, 400);
3347     d->run();
3348     delete d;
3349     }
3350    
3351 schoenebeck 2553 void MainWindow::mergeFiles(const std::vector<std::string>& filenames) {
3352     struct _Source {
3353     std::vector<RIFF::File*> riffs;
3354     std::vector<gig::File*> gigs;
3355    
3356     ~_Source() {
3357     for (int k = 0; k < gigs.size(); ++k) delete gigs[k];
3358     for (int k = 0; k < riffs.size(); ++k) delete riffs[k];
3359     riffs.clear();
3360     gigs.clear();
3361     }
3362     } sources;
3363    
3364     if (filenames.empty())
3365     throw RIFF::Exception(_("No files selected, so nothing done."));
3366    
3367     // first open all input files (to avoid output file corruption)
3368     int i;
3369     try {
3370     for (i = 0; i < filenames.size(); ++i) {
3371     const std::string& filename = filenames[i];
3372     printf("opening file=%s\n", filename.c_str());
3373    
3374     RIFF::File* riff = new RIFF::File(filename);
3375     sources.riffs.push_back(riff);
3376    
3377     gig::File* gig = new gig::File(riff);
3378     sources.gigs.push_back(gig);
3379     }
3380     } catch (RIFF::Exception e) {
3381     throw RIFF::Exception(
3382     _("Error occurred while opening '") +
3383     filenames[i] +
3384     "': " +
3385     e.Message
3386     );
3387     } catch (...) {
3388     throw RIFF::Exception(
3389     _("Unknown exception occurred while opening '") +
3390     filenames[i] + "'"
3391     );
3392     }
3393    
3394     // now merge the opened .gig files to the main .gig file currently being
3395     // open in gigedit
3396     try {
3397     for (i = 0; i < filenames.size(); ++i) {
3398     const std::string& filename = filenames[i];
3399     printf("merging file=%s\n", filename.c_str());
3400     assert(i < sources.gigs.size());
3401    
3402     this->file->AddContentOf(sources.gigs[i]);
3403     }
3404     } catch (RIFF::Exception e) {
3405     throw RIFF::Exception(
3406     _("Error occurred while merging '") +
3407     filenames[i] +
3408     "': " +
3409     e.Message
3410     );
3411     } catch (...) {
3412     throw RIFF::Exception(
3413     _("Unknown exception occurred while merging '") +
3414     filenames[i] + "'"
3415     );
3416     }
3417    
3418 schoenebeck 2683 // Finally save gig file persistently to disk ...
3419     //NOTE: requires that this gig file already has a filename !
3420     {
3421     std::cout << "Saving file\n" << std::flush;
3422     file_structure_to_be_changed_signal.emit(this->file);
3423    
3424     progress_dialog = new ProgressDialog( //FIXME: memory leak!
3425     _("Saving") + Glib::ustring(" '") +
3426     Glib::filename_display_basename(this->filename) + "' ...",
3427     *this
3428     );
3429     progress_dialog->show_all();
3430     saver = new Saver(this->file); //FIXME: memory leak!
3431     saver->signal_progress().connect(
3432     sigc::mem_fun(*this, &MainWindow::on_saver_progress));
3433     saver->signal_finished().connect(
3434     sigc::mem_fun(*this, &MainWindow::on_saver_finished));
3435     saver->signal_error().connect(
3436     sigc::mem_fun(*this, &MainWindow::on_saver_error));
3437     saver->launch();
3438     }
3439 schoenebeck 2553 }
3440    
3441     void MainWindow::on_action_merge_files() {
3442     if (this->file->GetFileName().empty()) {
3443     Glib::ustring txt = _(
3444     "You seem to have a new .gig file open that has not been saved "
3445     "yet. You must save it somewhere before starting to merge it with "
3446     "other .gig files though, because during the merge operation the "
3447     "other files' sample data must be written on file level to the "
3448     "target .gig file."
3449     );
3450     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
3451     msg.run();
3452     return;
3453     }
3454    
3455     Gtk::FileChooserDialog dialog(*this, _("Merge .gig files"));
3456 persson 2845 dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
3457 schoenebeck 2553 dialog.add_button(_("Merge"), Gtk::RESPONSE_OK);
3458     dialog.set_default_response(Gtk::RESPONSE_CANCEL);
3459     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
3460     Gtk::FileFilter filter;
3461     filter.add_pattern("*.gig");
3462     #else
3463     Glib::RefPtr<Gtk::FileFilter> filter = Gtk::FileFilter::create();
3464     filter->add_pattern("*.gig");
3465     #endif
3466     dialog.set_filter(filter);
3467     if (current_gig_dir != "") {
3468     dialog.set_current_folder(current_gig_dir);
3469     }
3470     dialog.set_select_multiple(true);
3471    
3472     // show warning in the file picker dialog
3473     Gtk::HBox descriptionArea;
3474     descriptionArea.set_spacing(15);
3475 persson 2845 Gtk::Image warningIcon;
3476     warningIcon.set_from_icon_name("dialog-warning",
3477     Gtk::IconSize(Gtk::ICON_SIZE_DIALOG));
3478 schoenebeck 2553 descriptionArea.pack_start(warningIcon, Gtk::PACK_SHRINK);
3479     #if GTKMM_MAJOR_VERSION < 3
3480     view::WrapLabel description;
3481     #else
3482     Gtk::Label description;
3483     description.set_line_wrap();
3484     #endif
3485     description.set_markup(_(
3486     "\nSelect at least one .gig file that shall be merged to the .gig file "
3487     "currently being open in gigedit.\n\n"
3488     "<b>Please Note:</b> Merging with other files will modify your "
3489     "currently open .gig file on file level! And be aware that the current "
3490     "merge algorithm does not detect duplicate samples yet. So if you are "
3491     "merging files which are using equivalent sample data, those "
3492     "equivalent samples will currently be treated as separate samples and "
3493     "will accordingly be stored separately in the target .gig file!"
3494     ));
3495     descriptionArea.pack_start(description);
3496     dialog.get_vbox()->pack_start(descriptionArea, Gtk::PACK_SHRINK);
3497     descriptionArea.show_all();
3498    
3499     if (dialog.run() == Gtk::RESPONSE_OK) {
3500 persson 2841 printf("on_action_merge_files self=%p\n",
3501     static_cast<void*>(Glib::Threads::Thread::self()));
3502 schoenebeck 2553 std::vector<std::string> filenames = dialog.get_filenames();
3503    
3504     // merge the selected files to the currently open .gig file
3505     try {
3506     mergeFiles(filenames);
3507     } catch (RIFF::Exception e) {
3508     Gtk::MessageDialog msg(*this, e.Message, false, Gtk::MESSAGE_ERROR);
3509     msg.run();
3510     }
3511    
3512     // update GUI
3513 schoenebeck 2772 __refreshEntireGUI();
3514 schoenebeck 2553 }
3515     }
3516    
3517 schoenebeck 1411 void MainWindow::set_file_is_shared(bool b) {
3518     this->file_is_shared = b;
3519    
3520     if (file_is_shared) {
3521     m_AttachedStateLabel.set_label(_("live-mode"));
3522     m_AttachedStateImage.set(
3523     Gdk::Pixbuf::create_from_xpm_data(status_attached_xpm)
3524     );
3525     } else {
3526     m_AttachedStateLabel.set_label(_("stand-alone"));
3527     m_AttachedStateImage.set(
3528     Gdk::Pixbuf::create_from_xpm_data(status_detached_xpm)
3529     );
3530     }
3531 schoenebeck 2689
3532     {
3533     Gtk::MenuItem* item = dynamic_cast<Gtk::MenuItem*>(
3534     uiManager->get_widget("/MenuBar/MenuSettings/SyncSamplerInstrumentSelection"));
3535     if (item) item->set_sensitive(b);
3536     }
3537 schoenebeck 1411 }
3538    
3539 schoenebeck 2621 void MainWindow::on_sample_ref_count_incremented(gig::Sample* sample, int offset) {
3540     if (!sample) return;
3541     sample_ref_count[sample] += offset;
3542     const int refcount = sample_ref_count[sample];
3543    
3544     Glib::RefPtr<Gtk::TreeModel> model = m_TreeViewSamples.get_model();
3545     for (int g = 0; g < model->children().size(); ++g) {
3546     Gtk::TreeModel::Row rowGroup = model->children()[g];
3547     for (int s = 0; s < rowGroup.children().size(); ++s) {
3548     Gtk::TreeModel::Row rowSample = rowGroup.children()[s];
3549     if (rowSample[m_SamplesModel.m_col_sample] != sample) continue;
3550     rowSample[m_SamplesModel.m_col_refcount] = ToString(refcount) + " " + _("Refs.");
3551 schoenebeck 2625 rowSample[m_SamplesModel.m_color] = refcount ? "black" : "red";
3552 schoenebeck 2621 }
3553     }
3554     }
3555    
3556     void MainWindow::on_sample_ref_changed(gig::Sample* oldSample, gig::Sample* newSample) {
3557     on_sample_ref_count_incremented(oldSample, -1);
3558     on_sample_ref_count_incremented(newSample, +1);
3559     }
3560    
3561     void MainWindow::on_samples_to_be_removed(std::list<gig::Sample*> samples) {
3562     // just in case a new sample is added later with exactly the same memory
3563     // address, which would lead to incorrect refcount if not deleted here
3564     for (std::list<gig::Sample*>::const_iterator it = samples.begin();
3565 schoenebeck 2666 it != samples.end(); ++it)
3566 schoenebeck 2621 {
3567     sample_ref_count.erase(*it);
3568     }
3569     }
3570    
3571 schoenebeck 2625 void MainWindow::show_samples_tab() {
3572     m_TreeViewNotebook.set_current_page(0);
3573     }
3574    
3575     void MainWindow::show_intruments_tab() {
3576     m_TreeViewNotebook.set_current_page(1);
3577     }
3578    
3579     void MainWindow::show_scripts_tab() {
3580     m_TreeViewNotebook.set_current_page(2);
3581     }
3582    
3583 schoenebeck 1339 sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {
3584 schoenebeck 1322 return file_structure_to_be_changed_signal;
3585     }
3586    
3587 schoenebeck 1339 sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_changed() {
3588 schoenebeck 1322 return file_structure_changed_signal;
3589     }
3590    
3591 schoenebeck 1339 sigc::signal<void, std::list<gig::Sample*> >& MainWindow::signal_samples_to_be_removed() {
3592 schoenebeck 1322 return samples_to_be_removed_signal;
3593     }
3594    
3595 schoenebeck 1339 sigc::signal<void>& MainWindow::signal_samples_removed() {
3596 schoenebeck 1322 return samples_removed_signal;
3597     }
3598    
3599 schoenebeck 1339 sigc::signal<void, gig::Region*>& MainWindow::signal_region_to_be_changed() {
3600 schoenebeck 1322 return region_to_be_changed_signal;
3601     }
3602    
3603 schoenebeck 1339 sigc::signal<void, gig::Region*>& MainWindow::signal_region_changed() {
3604 schoenebeck 1322 return region_changed_signal;
3605     }
3606    
3607 schoenebeck 1853 sigc::signal<void, gig::Sample*>& MainWindow::signal_sample_changed() {
3608     return sample_changed_signal;
3609     }
3610    
3611 schoenebeck 1339 sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& MainWindow::signal_sample_ref_changed() {
3612 schoenebeck 1322 return sample_ref_changed_signal;
3613     }
3614    
3615 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_to_be_changed() {
3616 schoenebeck 1322 return dimreg_to_be_changed_signal;
3617     }
3618    
3619 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_changed() {
3620 schoenebeck 1322 return dimreg_changed_signal;
3621     }
3622 schoenebeck 1654
3623     sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_note_on() {
3624     return note_on_signal;
3625     }
3626    
3627     sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_note_off() {
3628     return note_off_signal;
3629     }
3630 schoenebeck 1660
3631     sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_keyboard_key_hit() {
3632     return m_RegionChooser.signal_keyboard_key_hit();
3633     }
3634    
3635     sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_keyboard_key_released() {
3636     return m_RegionChooser.signal_keyboard_key_released();
3637     }
3638 schoenebeck 2689
3639     sigc::signal<void, gig::Instrument*>& MainWindow::signal_switch_sampler_instrument() {
3640     return switch_sampler_instrument_signal;
3641     }

  ViewVC Help
Powered by ViewVC