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