/[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 2701 - (hide annotations) (download)
Mon Jan 12 23:28:04 2015 UTC (9 years, 2 months ago) by schoenebeck
File size: 124674 byte(s)
* Implemented reordering of instruments by drag & drop.

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

  ViewVC Help
Powered by ViewVC