/[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 3225 - (hide annotations) (download)
Fri May 26 22:10:16 2017 UTC (6 years, 10 months ago) by schoenebeck
File size: 156604 byte(s)
* Assigned more useful default dimensions (and default position) for various
  windows and dialogs (if auto-restore of user's own custom window
  dimensions is disabled).
* Bumped version (1.0.0.svn51).

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

  ViewVC Help
Powered by ViewVC