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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2976 - (hide annotations) (download)
Thu Jul 28 06:47:25 2016 UTC (4 years, 4 months ago) by schoenebeck
File size: 29714 byte(s)
* Fixed crash when opening dimension manager dialolg multiple times
  (and i.e. adding or removing dimensions each time).
* Bumped version (1.0.0.svn21).

1 persson 2169 /*
2 persson 2507 * Copyright (C) 2006-2014 Andreas Persson
3 schoenebeck 1225 *
4     * This program is free software; you can redistribute it and/or
5     * modify it under the terms of the GNU General Public License as
6     * published by the Free Software Foundation; either version 2, or (at
7     * your option) any later version.
8     *
9     * This program is distributed in the hope that it will be useful, but
10     * WITHOUT ANY WARRANTY; without even the implied warranty of
11     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12     * General Public License for more details.
13     *
14     * You should have received a copy of the GNU General Public License
15     * along with program; see the file COPYING. If not, write to the Free
16     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17     * 02110-1301 USA.
18     */
19    
20 persson 2844 #include <glibmmconfig.h>
21     // threads.h must be included first to be able to build with
22     // G_DISABLE_DEPRECATED
23     #if (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION == 31 && GLIBMM_MICRO_VERSION >= 2) || \
24     (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION > 31) || GLIBMM_MAJOR_VERSION > 2
25     #include <glibmm/threads.h>
26     #endif
27    
28 schoenebeck 1225 #include "dimensionmanager.h"
29    
30     #include <gtkmm/messagedialog.h>
31     #include <gtkmm/dialog.h>
32     #include <gtkmm/comboboxtext.h>
33 persson 1733 #include <gtkmm/spinbutton.h>
34     #include <gtkmm/table.h>
35 schoenebeck 1225
36 persson 1831 #include "global.h"
37 persson 2169 #include "compat.h"
38 persson 1831
39 schoenebeck 1225 // returns a human readable name of the given dimension type
40 schoenebeck 2558 Glib::ustring dimTypeAsString(gig::dimension_t d) {
41 schoenebeck 1225 char buf[32];
42     switch (d) {
43     case gig::dimension_none:
44 persson 1831 return _("None");
45 schoenebeck 1225 case gig::dimension_samplechannel:
46 persson 1831 return _("Sample Channel");
47 schoenebeck 1225 case gig::dimension_layer:
48 persson 1831 return _("Layer");
49 schoenebeck 1225 case gig::dimension_velocity:
50 persson 1831 return _("Velocity");
51 schoenebeck 1225 case gig::dimension_channelaftertouch:
52 persson 1831 return _("Aftertouch");
53 schoenebeck 1225 case gig::dimension_releasetrigger:
54 persson 1831 return _("Release Trigger");
55 schoenebeck 1225 case gig::dimension_keyboard:
56 persson 1831 return _("Keyswitching");
57 schoenebeck 1225 case gig::dimension_roundrobin:
58 persson 1831 return _("Round Robin");
59 schoenebeck 1225 case gig::dimension_random:
60 persson 1831 return _("Random Generator");
61 schoenebeck 1225 case gig::dimension_smartmidi:
62 persson 1831 return _("Smart MIDI");
63 schoenebeck 1225 case gig::dimension_roundrobinkeyboard:
64 persson 1831 return _("Keyboard Round Robin");
65 schoenebeck 1225 case gig::dimension_modwheel:
66 persson 1831 return _("Modulation Wheel");
67 schoenebeck 1225 case gig::dimension_breath:
68 persson 1831 return _("Breath Ctrl.");
69 schoenebeck 1225 case gig::dimension_foot:
70 persson 1831 return _("Foot Ctrl.");
71 schoenebeck 1225 case gig::dimension_portamentotime:
72 persson 1831 return _("Portamento Time Ctrl.");
73 schoenebeck 1225 case gig::dimension_effect1:
74 persson 1831 return _("Effect Ctrl. 1");
75 schoenebeck 1225 case gig::dimension_effect2:
76 persson 1831 return _("Effect Ctrl. 2");
77 schoenebeck 1225 case gig::dimension_genpurpose1:
78 persson 1831 return _("General Purpose Ctrl. 1");
79 schoenebeck 1225 case gig::dimension_genpurpose2:
80 persson 1831 return _("General Purpose Ctrl. 2");
81 schoenebeck 1225 case gig::dimension_genpurpose3:
82 persson 1831 return _("General Purpose Ctrl. 3");
83 schoenebeck 1225 case gig::dimension_genpurpose4:
84 persson 1831 return _("General Purpose Ctrl. 4");
85 schoenebeck 1225 case gig::dimension_sustainpedal:
86 persson 1831 return _("Sustain Pedal");
87 schoenebeck 1225 case gig::dimension_portamento:
88 persson 1831 return _("Portamento Ctrl.");
89 schoenebeck 1225 case gig::dimension_sostenutopedal:
90 persson 1831 return _("Sostenuto Pedal");
91 schoenebeck 1225 case gig::dimension_softpedal:
92 persson 1831 return _("Soft Pedal");
93 schoenebeck 1225 case gig::dimension_genpurpose5:
94 persson 1831 return _("General Purpose Ctrl. 5");
95 schoenebeck 1225 case gig::dimension_genpurpose6:
96 persson 1831 return _("General Purpose Ctrl. 6");
97 schoenebeck 1225 case gig::dimension_genpurpose7:
98 persson 1831 return _("General Purpose Ctrl. 7");
99 schoenebeck 1225 case gig::dimension_genpurpose8:
100 persson 1831 return _("General Purpose Ctrl. 8");
101 schoenebeck 1225 case gig::dimension_effect1depth:
102 persson 1831 return _("Effect 1 Depth");
103 schoenebeck 1225 case gig::dimension_effect2depth:
104 persson 1831 return _("Effect 2 Depth");
105 schoenebeck 1225 case gig::dimension_effect3depth:
106 persson 1831 return _("Effect 3 Depth");
107 schoenebeck 1225 case gig::dimension_effect4depth:
108 persson 1831 return _("Effect 4 Depth");
109 schoenebeck 1225 case gig::dimension_effect5depth:
110 persson 1831 return _("Effect 5 Depth");
111 schoenebeck 1225 default:
112     sprintf(buf, "Unknown Type (0x%x) !!!", d);
113     return buf;
114     }
115     }
116    
117     // returns a human readable description of the given dimension
118     static Glib::ustring __dimDescriptionAsString(gig::dimension_t d) {
119     switch (d) {
120     case gig::dimension_none:
121 persson 1831 return _("Dimension not in use");
122 schoenebeck 1225 case gig::dimension_samplechannel:
123 persson 1831 return _("If used sample has more than one channel (thus is not mono)");
124 schoenebeck 1225 case gig::dimension_layer:
125 persson 1831 return _("For layering of up to 8 instruments (and eventually crossfading of 2 or 4 layers");
126 schoenebeck 1225 case gig::dimension_velocity:
127 persson 1831 return _("Key Velocity (this is the only dimension in gig2 where the ranges can exactly be defined)");
128 schoenebeck 1225 case gig::dimension_channelaftertouch:
129 persson 1831 return _("Channel Key Pressure");
130 schoenebeck 1225 case gig::dimension_releasetrigger:
131 persson 1831 return _("Special dimension for triggering samples on releasing a key");
132 schoenebeck 1225 case gig::dimension_keyboard:
133 persson 1831 return _("Dimension for keyswitching (keyboard)");
134 schoenebeck 1225 case gig::dimension_roundrobin:
135 persson 1831 return _("Different samples triggered each time a note is played, dimension regions selected in sequence");
136 schoenebeck 1225 case gig::dimension_random:
137 persson 1831 return _("Different samples triggered each time a note is played, random order");
138 schoenebeck 1225 case gig::dimension_smartmidi:
139 persson 1831 return _("For MIDI tools like legato and repetition mode");
140 schoenebeck 1225 case gig::dimension_roundrobinkeyboard:
141 persson 1831 return _("Different samples triggered each time a note is played, any key advances the counter");
142 schoenebeck 1225 case gig::dimension_modwheel:
143 persson 1831 return _("MIDI Controller 1");
144 schoenebeck 1225 case gig::dimension_breath:
145 persson 1831 return _("MIDI Controller 2");
146 schoenebeck 1225 case gig::dimension_foot:
147 persson 1831 return _("MIDI Controller 4");
148 schoenebeck 1225 case gig::dimension_portamentotime:
149 persson 1831 return _("MIDI Controller 5");
150 schoenebeck 1225 case gig::dimension_effect1:
151 persson 1831 return _("MIDI Controller 12");
152 schoenebeck 1225 case gig::dimension_effect2:
153 persson 1831 return _("MIDI Controller 13");
154 schoenebeck 1225 case gig::dimension_genpurpose1:
155 persson 1831 return _("Slider, MIDI Controller 16");
156 schoenebeck 1225 case gig::dimension_genpurpose2:
157 persson 1831 return _("Slider, MIDI Controller 17");
158 schoenebeck 1225 case gig::dimension_genpurpose3:
159 persson 1831 return _("Slider, MIDI Controller 18");
160 schoenebeck 1225 case gig::dimension_genpurpose4:
161 persson 1831 return _("Slider, MIDI Controller 19");
162 schoenebeck 1225 case gig::dimension_sustainpedal:
163 persson 1831 return _("MIDI Controller 64");
164 schoenebeck 1225 case gig::dimension_portamento:
165 persson 1831 return _("MIDI Controller 65");
166 schoenebeck 1225 case gig::dimension_sostenutopedal:
167 persson 1831 return _("MIDI Controller 66");
168 schoenebeck 1225 case gig::dimension_softpedal:
169 persson 1831 return _("MIDI Controller 67");
170 schoenebeck 1225 case gig::dimension_genpurpose5:
171 persson 1831 return _("Button, MIDI Controller 80");
172 schoenebeck 1225 case gig::dimension_genpurpose6:
173 persson 1831 return _("Button, MIDI Controller 81");
174 schoenebeck 1225 case gig::dimension_genpurpose7:
175 persson 1831 return _("Button, MIDI Controller 82");
176 schoenebeck 1225 case gig::dimension_genpurpose8:
177 persson 1831 return _("Button, MIDI Controller 83");
178 schoenebeck 1225 case gig::dimension_effect1depth:
179 persson 1831 return _("MIDI Controller 91");
180 schoenebeck 1225 case gig::dimension_effect2depth:
181 persson 1831 return _("MIDI Controller 92");
182 schoenebeck 1225 case gig::dimension_effect3depth:
183 persson 1831 return _("MIDI Controller 93");
184 schoenebeck 1225 case gig::dimension_effect4depth:
185 persson 1831 return _("MIDI Controller 94");
186 schoenebeck 1225 case gig::dimension_effect5depth:
187 persson 1831 return _("MIDI Controller 95");
188 schoenebeck 1225 default:
189 persson 1831 return _("Please report this !!!");
190 schoenebeck 1225 }
191     }
192    
193 schoenebeck 2562 DimTypeCellRenderer::DimTypeCellRenderer() :
194     Glib::ObjectBase(typeid(DimTypeCellRenderer)),
195     Gtk::CellRendererText(),
196     m_propertyDimType(*this, "gigdimension_t", gig::dimension_none),
197     m_propertyUsageCount(*this, "intusagecount", 0),
198     m_propertyTotalRegions(*this, "inttotalregions", 0)
199     {
200     propertyDimType().signal_changed().connect(
201     sigc::mem_fun(*this, &DimTypeCellRenderer::typeChanged)
202     );
203     propertyUsageCount().signal_changed().connect(
204     sigc::mem_fun(*this, &DimTypeCellRenderer::statsChanged)
205     );
206     propertyTotalRegions().signal_changed().connect(
207     sigc::mem_fun(*this, &DimTypeCellRenderer::statsChanged)
208     );
209     }
210    
211     void DimTypeCellRenderer::typeChanged() {
212     gig::dimension_t type = propertyDimType();
213     Glib::ustring s = dimTypeAsString(type);
214     property_text() = s;
215     }
216    
217     void DimTypeCellRenderer::statsChanged() {
218     int usageCount = propertyUsageCount();
219     int totalRegions = propertyTotalRegions();
220     bool bDimensionExistsOnAllRegions = (usageCount == totalRegions);
221     property_foreground() = ((bDimensionExistsOnAllRegions) ? "black" : "gray");
222     }
223    
224     IntSetCellRenderer::IntSetCellRenderer() :
225     Glib::ObjectBase(typeid(IntSetCellRenderer)),
226     Gtk::CellRendererText(),
227     m_propertyValue(*this, "stdintset", std::set<int>())
228     {
229     propertyValue().signal_changed().connect(
230     sigc::mem_fun(*this, &IntSetCellRenderer::valueChanged)
231     );
232     }
233    
234     void IntSetCellRenderer::valueChanged() {
235     Glib::ustring s;
236     std::set<int> v = propertyValue();
237     for (std::set<int>::const_iterator it = v.begin(); it != v.end(); ++it) {
238     s += ToString(*it);
239     if (*it != *v.rbegin()) s += "|";
240     }
241     property_text() = s;
242     property_foreground() = (v.size() > 1) ? "gray" : "black";
243     }
244    
245 schoenebeck 1225 DimensionManager::DimensionManager() :
246 persson 2845 addButton(_("_Add"), true),
247     removeButton(_("_Remove"), true),
248     allRegionsCheckBox(_("All Regions"))
249 schoenebeck 1225 {
250 schoenebeck 2641 ignoreColumnClicked = true;
251    
252 persson 1831 set_title(_("Dimensions of selected Region"));
253 schoenebeck 1225 add(vbox);
254     scrolledWindow.add(treeView);
255     vbox.pack_start(scrolledWindow);
256     scrolledWindow.show();
257 schoenebeck 1411 vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
258 schoenebeck 1225 buttonBox.set_layout(Gtk::BUTTONBOX_END);
259     buttonBox.set_border_width(5);
260     buttonBox.show();
261 schoenebeck 2562 buttonBox.pack_start(allRegionsCheckBox, Gtk::PACK_EXPAND_PADDING);
262 schoenebeck 1411 buttonBox.pack_start(addButton, Gtk::PACK_SHRINK);
263     buttonBox.pack_start(removeButton, Gtk::PACK_SHRINK);
264 schoenebeck 1225 addButton.show();
265     removeButton.show();
266 schoenebeck 2562 allRegionsCheckBox.set_tooltip_text(
267     _("Enable this if you want to edit dimensions of all regions simultaniously.")
268     );
269 schoenebeck 1225
270     // setup the table
271     refTableModel = Gtk::ListStore::create(tableModel);
272     treeView.set_model(refTableModel);
273 schoenebeck 2562 treeView.append_column(_("Dimension Type"), m_cellRendererDimType);
274     treeView.append_column(_("Bits"), m_cellRendererIntSet);
275     treeView.append_column(_("Zones"), m_cellRendererIntSet);
276 persson 1831 treeView.append_column(_("Description"), tableModel.m_description);
277 schoenebeck 2562 treeView.get_column(0)->add_attribute(m_cellRendererDimType.propertyDimType(), tableModel.m_type);
278     treeView.get_column(0)->add_attribute(m_cellRendererDimType.propertyUsageCount(), tableModel.m_usageCount);
279     treeView.get_column(0)->add_attribute(m_cellRendererDimType.propertyTotalRegions(), tableModel.m_totalRegions);
280     treeView.get_column(1)->add_attribute(m_cellRendererIntSet.propertyValue(), tableModel.m_bits);
281     treeView.get_column(2)->add_attribute(m_cellRendererIntSet.propertyValue(), tableModel.m_zones);
282 schoenebeck 1225 treeView.show();
283    
284 schoenebeck 2641 treeView.signal_cursor_changed().connect(
285     sigc::mem_fun(*this, &DimensionManager::onColumnClicked)
286     );
287    
288 schoenebeck 1225 addButton.signal_clicked().connect(
289     sigc::mem_fun(*this, &DimensionManager::addDimension)
290     );
291    
292     removeButton.signal_clicked().connect(
293     sigc::mem_fun(*this, &DimensionManager::removeDimension)
294     );
295 schoenebeck 2562 allRegionsCheckBox.signal_toggled().connect(
296     sigc::mem_fun(*this, &DimensionManager::onAllRegionsCheckBoxToggled)
297     );
298 schoenebeck 1225
299     show_all_children();
300 schoenebeck 2558
301     resize(460,300);
302 schoenebeck 1225 }
303    
304 schoenebeck 2562 bool DimensionManager::allRegions() const {
305     return allRegionsCheckBox.get_active();
306     }
307    
308     void DimensionManager::onAllRegionsCheckBoxToggled() {
309     set_title(
310     allRegions() ? _("Dimensions of all Regions") : _("Dimensions of selected Region")
311     );
312     treeView.set_tooltip_text(
313     allRegions()
314     ? _("Dimensions and numbers in gray indicates a difference among the individual regions.")
315     : _("You are currently only viewing dimensions of the currently selected region.")
316     );
317     refreshManager();
318     }
319    
320     // following two data types are just used in DimensionManager::refresManager(),
321     // due to the maps template nature however, they must be declared at global
322     // space to avoid compilation errors
323     struct _DimDef {
324     std::set<int> bits;
325     std::set<int> zones;
326     int usageCount;
327     };
328     typedef std::map<gig::dimension_t, _DimDef> _Dimensions;
329    
330 schoenebeck 1225 // update all GUI elements according to current gig::Region informations
331     void DimensionManager::refreshManager() {
332 schoenebeck 2562 set_sensitive(false);
333 schoenebeck 1225 refTableModel->clear();
334 schoenebeck 2562 if (allRegions()) {
335     if (region) {
336     _Dimensions dims;
337     gig::Instrument* instr = (gig::Instrument*)region->GetParent();
338     int iRegionsCount = 0;
339     for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion(), ++iRegionsCount) {
340     for (uint i = 0; i < rgn->Dimensions; i++) {
341     gig::dimension_def_t* dim = &rgn->pDimensionDefinitions[i];
342     dims[dim->dimension].bits.insert(dim->bits);
343     dims[dim->dimension].zones.insert(dim->zones);
344     dims[dim->dimension].usageCount++;
345     }
346     }
347     for (_Dimensions::const_iterator it = dims.begin(); it != dims.end(); ++it) {
348     Gtk::TreeModel::Row row = *(refTableModel->append());
349     row[tableModel.m_type] = it->first;
350     row[tableModel.m_bits] = it->second.bits;
351     row[tableModel.m_zones] = it->second.zones;
352     row[tableModel.m_description] = __dimDescriptionAsString(it->first);
353     row[tableModel.m_usageCount] = it->second.usageCount;
354     row[tableModel.m_totalRegions] = iRegionsCount;
355     }
356 persson 1677 }
357 schoenebeck 2562 } else {
358     if (region) {
359     for (uint i = 0; i < region->Dimensions; i++) {
360     gig::dimension_def_t* dim = &region->pDimensionDefinitions[i];
361     Gtk::TreeModel::Row row = *(refTableModel->append());
362     std::set<int> vBits;
363     vBits.insert(dim->bits);
364     row[tableModel.m_bits] = vBits;
365     std::set<int> vZones;
366     vZones.insert(dim->zones);
367     row[tableModel.m_zones] = vZones;
368     row[tableModel.m_description] = __dimDescriptionAsString(dim->dimension);
369     row[tableModel.m_type] = dim->dimension;
370     row[tableModel.m_usageCount] = 1;
371     row[tableModel.m_totalRegions] = 1;
372     }
373     }
374 schoenebeck 1225 }
375 persson 1677 set_sensitive(region);
376 schoenebeck 1225 }
377    
378     void DimensionManager::show(gig::Region* region) {
379 schoenebeck 2641 ignoreColumnClicked = true;
380 schoenebeck 1225 this->region = region;
381     refreshManager();
382     Gtk::Window::show();
383     deiconify();
384 schoenebeck 2641 ignoreColumnClicked = false;
385 schoenebeck 1225 }
386    
387 persson 1677 void DimensionManager::set_region(gig::Region* region) {
388 schoenebeck 2641 ignoreColumnClicked = true;
389 persson 1677 this->region = region;
390     refreshManager();
391 schoenebeck 2641 ignoreColumnClicked = false;
392 persson 1677 }
393    
394 schoenebeck 2641 void DimensionManager::onColumnClicked() {
395 schoenebeck 2919 printf("DimensionManager::onColumnClicked()\n");
396    
397     //FIXME: BUG: this method is currently very unreliably called, it should actually be called when the user selects another column, it is ATM however also called when the table content changed programmatically causing the dialog below to popup at undesired times !
398    
399 schoenebeck 2641 //HACK: Prevents that onColumnClicked() gets called multiple times or at times where it is not desired
400     if (ignoreColumnClicked) {
401     ignoreColumnClicked = false;
402     return;
403     }
404 schoenebeck 2921 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 18) || GTKMM_MAJOR_VERSION > 2
405 schoenebeck 2919 // prevents app to crash if this dialog is closed
406     if (!get_visible())
407     return;
408 schoenebeck 2921 #else
409     # warning Your GTKMM version is too old; dimension manager dialog might crash when changing a dimension type !
410     #endif
411 schoenebeck 2641
412 schoenebeck 2976 #if (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION >= 8) || GTKMM_MAJOR_VERSION > 3
413     if (!is_visible()) return;
414     #endif
415    
416 schoenebeck 2641 Gtk::TreeModel::Path path;
417     Gtk::TreeViewColumn* focus_column;
418     treeView.get_cursor(path, focus_column);
419     //const int row = path[0];
420     if (focus_column == treeView.get_column(0)) {
421     Gtk::TreeModel::iterator it = treeView.get_model()->get_iter(path);
422 schoenebeck 2976 if (!it) return;
423 schoenebeck 2641 Gtk::TreeModel::Row row = *it;
424     gig::dimension_t oldType = row[tableModel.m_type];
425    
426     Gtk::Dialog dialog(_("Change Dimension"), true /*modal*/);
427     int oldTypeIndex = -1;
428     Glib::RefPtr<Gtk::ListStore> refComboModel = Gtk::ListStore::create(comboModel);
429     for (int i = 0x01, count = 0; i < 0xff; i++) {
430     Glib::ustring sType =
431     dimTypeAsString(static_cast<gig::dimension_t>(i));
432     if (i == oldType) oldTypeIndex = count;
433     if (sType.find("Unknown") != 0) {
434     Gtk::TreeModel::Row row = *(refComboModel->append());
435     row[comboModel.m_type_id] = i;
436     row[comboModel.m_type_name] = sType;
437     count++;
438     }
439     }
440     Gtk::Table table(1, 2);
441     Gtk::Label labelDimType(_("Dimension:"), Gtk::ALIGN_START);
442     Gtk::ComboBox comboDimType;
443     comboDimType.set_model(refComboModel);
444     comboDimType.pack_start(comboModel.m_type_id);
445     comboDimType.pack_start(comboModel.m_type_name);
446     table.attach(labelDimType, 0, 1, 0, 1);
447     table.attach(comboDimType, 1, 2, 0, 1);
448     dialog.get_vbox()->pack_start(table);
449    
450 persson 2845 dialog.add_button(_("_OK"), 0);
451     dialog.add_button(_("_Cancel"), 1);
452 schoenebeck 2641 dialog.show_all_children();
453    
454     comboDimType.set_active(oldTypeIndex);
455    
456     if (!dialog.run()) { // OK selected ...
457 schoenebeck 2919 ignoreColumnClicked = true;
458 schoenebeck 2641 Gtk::TreeModel::iterator iterType = comboDimType.get_active();
459     if (!iterType) return;
460     Gtk::TreeModel::Row rowType = *iterType;
461     if (!rowType) return;
462     int iTypeID = rowType[comboModel.m_type_id];
463     gig::dimension_t newType = static_cast<gig::dimension_t>(iTypeID);
464     if (newType == oldType) return;
465     //printf("change 0x%x -> 0x%x\n", oldType, newType);
466    
467     // assemble the list of regions where the selected dimension type
468     // shall be changed
469     std::vector<gig::Region*> vRegions;
470     if (allRegions()) {
471     gig::Instrument* instr = (gig::Instrument*)region->GetParent();
472     for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
473     if (rgn->GetDimensionDefinition(oldType)) vRegions.push_back(rgn);
474     }
475     } else vRegions.push_back(region);
476    
477     std::set<Glib::ustring> errors;
478    
479     for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
480     gig::Region* region = vRegions[iRgn];
481     try {
482     // notify everybody that we're going to update the region
483     region_to_be_changed_signal.emit(region);
484     // change the dimension type on that region
485     region->SetDimensionType(oldType, newType);
486     // let everybody know there was a change
487     region_changed_signal.emit(region);
488     } catch (RIFF::Exception e) {
489     // notify that the changes are over (i.e. to avoid dead locks)
490     region_changed_signal.emit(region);
491     Glib::ustring txt = _("Could not alter dimension: ") + e.Message;
492     if (vRegions.size() == 1) {
493     // show error message directly
494     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
495     msg.run();
496     } else {
497     // remember error, they are shown after all regions have been processed
498     errors.insert(txt);
499     }
500     }
501     }
502     // update all GUI elements
503     refreshManager();
504    
505     if (!errors.empty()) {
506     Glib::ustring txt = _(
507     "The following errors occurred while trying to change the dimension type on all regions:"
508     );
509     txt += "\n\n";
510     for (std::set<Glib::ustring>::const_iterator it = errors.begin();
511     it != errors.end(); ++it)
512     {
513     txt += "-> " + *it + "\n";
514     }
515     txt += "\n";
516     txt += _(
517     "You might also want to check the console for further warnings and "
518     "error messages."
519     );
520     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
521     msg.run();
522     }
523     }
524     }
525     }
526    
527 schoenebeck 1225 void DimensionManager::addDimension() {
528 schoenebeck 2562 Gtk::Dialog dialog(_("New Dimension"), true /*modal*/);
529     // add dimension type combo box to the dialog
530     Glib::RefPtr<Gtk::ListStore> refComboModel = Gtk::ListStore::create(comboModel);
531     for (int i = 0x01; i < 0xff; i++) {
532     Glib::ustring sType =
533     dimTypeAsString(static_cast<gig::dimension_t>(i));
534     if (sType.find("Unknown") != 0) {
535     Gtk::TreeModel::Row row = *(refComboModel->append());
536     row[comboModel.m_type_id] = i;
537     row[comboModel.m_type_name] = sType;
538 schoenebeck 1225 }
539 schoenebeck 2562 }
540     Gtk::Table table(2, 2);
541     Gtk::Label labelDimType(_("Dimension:"), Gtk::ALIGN_START);
542     Gtk::ComboBox comboDimType;
543     comboDimType.set_model(refComboModel);
544     comboDimType.pack_start(comboModel.m_type_id);
545     comboDimType.pack_start(comboModel.m_type_name);
546     Gtk::Label labelZones(_("Zones:"), Gtk::ALIGN_START);
547     table.attach(labelDimType, 0, 1, 0, 1);
548     table.attach(comboDimType, 1, 2, 0, 1);
549     table.attach(labelZones, 0, 1, 1, 2);
550     dialog.get_vbox()->pack_start(table);
551 persson 1733
552 schoenebeck 2562 // number of zones: use a combo box with fix values for gig
553     // v2 and a spin button for v3
554     Gtk::ComboBoxText comboZones;
555     Gtk::SpinButton spinZones;
556     bool version2 = false;
557     if (region) {
558     gig::File* file = (gig::File*)region->GetParent()->GetParent();
559     version2 = file->pVersion && file->pVersion->major == 2;
560     }
561     if (version2) {
562     for (int i = 1; i <= 5; i++) {
563     char buf[3];
564     sprintf(buf, "%d", 1 << i);
565 persson 2507 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
566 schoenebeck 2562 comboZones.append_text(buf);
567 persson 2169 #else
568 schoenebeck 2562 comboZones.append(buf);
569 persson 2169 #endif
570 schoenebeck 2562 }
571     table.attach(comboZones, 1, 2, 1, 2);
572     } else {
573     spinZones.set_increments(1, 8);
574     spinZones.set_numeric(true);
575     spinZones.set_range(2, 128);
576     spinZones.set_value(2);
577     table.attach(spinZones, 1, 2, 1, 2);
578     }
579    
580 persson 2845 dialog.add_button(_("_OK"), 0);
581     dialog.add_button(_("_Cancel"), 1);
582 schoenebeck 2562 dialog.show_all_children();
583    
584     if (!dialog.run()) { // OK selected ...
585     Gtk::TreeModel::iterator iterType = comboDimType.get_active();
586     if (!iterType) return;
587     Gtk::TreeModel::Row rowType = *iterType;
588     if (!rowType) return;
589     int iTypeID = rowType[comboModel.m_type_id];
590     gig::dimension_t type = static_cast<gig::dimension_t>(iTypeID);
591     gig::dimension_def_t dim;
592     dim.dimension = type;
593    
594     if (version2) {
595     if (comboZones.get_active_row_number() < 0) return;
596     dim.bits = comboZones.get_active_row_number() + 1;
597     dim.zones = 1 << dim.bits;
598 persson 1733 } else {
599 schoenebeck 2562 dim.zones = spinZones.get_value_as_int();
600     dim.bits = zoneCountToBits(dim.zones);
601 persson 1733 }
602    
603 schoenebeck 2562 // assemble the list of regions where the selected dimension shall be
604     // added to
605     std::vector<gig::Region*> vRegions;
606     if (allRegions()) {
607     gig::Instrument* instr = (gig::Instrument*)region->GetParent();
608     for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
609     if (!rgn->GetDimensionDefinition(type)) vRegions.push_back(rgn);
610     }
611     } else vRegions.push_back(region);
612    
613     std::set<Glib::ustring> errors;
614 persson 1733
615 schoenebeck 2562 for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
616     gig::Region* region = vRegions[iRgn];
617     try {
618     printf(
619     "Adding dimension (type=0x%x, bits=%d, zones=%d)\n",
620     dim.dimension, dim.bits, dim.zones
621     );
622     // notify everybody that we're going to update the region
623     region_to_be_changed_signal.emit(region);
624     // add the new dimension to the region
625     // (implicitly creates new dimension regions)
626     region->AddDimension(&dim);
627     // let everybody know there was a change
628     region_changed_signal.emit(region);
629     } catch (RIFF::Exception e) {
630     // notify that the changes are over (i.e. to avoid dead locks)
631     region_changed_signal.emit(region);
632     Glib::ustring txt = _("Could not add dimension: ") + e.Message;
633     if (vRegions.size() == 1) {
634     // show error message directly
635     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
636     msg.run();
637     } else {
638     // remember error, they are shown after all regions have been processed
639     errors.insert(txt);
640     }
641     }
642     }
643     // update all GUI elements
644     refreshManager();
645 persson 1733
646 schoenebeck 2562 if (!errors.empty()) {
647     Glib::ustring txt = _(
648     "The following errors occurred while trying to create the dimension on all regions:"
649     );
650     txt += "\n\n";
651     for (std::set<Glib::ustring>::const_iterator it = errors.begin();
652     it != errors.end(); ++it)
653     {
654     txt += "-> " + *it + "\n";
655 persson 1733 }
656 schoenebeck 2562 txt += "\n";
657     txt += _(
658     "You might also want to check the console for further warnings and "
659     "error messages."
660 schoenebeck 1225 );
661 schoenebeck 2562 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
662     msg.run();
663 schoenebeck 1225 }
664     }
665     }
666    
667 schoenebeck 2562 void DimensionManager::removeDimension() {
668 schoenebeck 1225 Glib::RefPtr<Gtk::TreeSelection> sel = treeView.get_selection();
669     Gtk::TreeModel::iterator it = sel->get_selected();
670     if (it) {
671 schoenebeck 2562 Gtk::TreeModel::Row row = *it;
672     gig::dimension_t type = row[tableModel.m_type];
673    
674     // assemble the list of regions where the selected dimension shall be
675     // added to
676     std::vector<gig::Region*> vRegions;
677     if (allRegions()) {
678     gig::Instrument* instr = (gig::Instrument*)region->GetParent();
679     for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
680     if (rgn->GetDimensionDefinition(type)) vRegions.push_back(rgn);
681     }
682     } else vRegions.push_back(region);
683    
684     std::set<Glib::ustring> errors;
685    
686     for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
687     gig::Region* region = vRegions[iRgn];
688     gig::dimension_def_t* dim = region->GetDimensionDefinition(type);
689     try {
690     // notify everybody that we're going to update the region
691     region_to_be_changed_signal.emit(region);
692     // remove selected dimension
693     region->DeleteDimension(dim);
694     // let everybody know there was a change
695     region_changed_signal.emit(region);
696     } catch (RIFF::Exception e) {
697     // notify that the changes are over (i.e. to avoid dead locks)
698     region_changed_signal.emit(region);
699     Glib::ustring txt = _("Could not remove dimension: ") + e.Message;
700     if (vRegions.size() == 1) {
701     // show error message directly
702     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
703     msg.run();
704     } else {
705     // remember error, they are shown after all regions have been processed
706     errors.insert(txt);
707     }
708     }
709     }
710     // update all GUI elements
711     refreshManager();
712    
713     if (!errors.empty()) {
714     Glib::ustring txt = _(
715     "The following errors occurred while trying to remove the dimension from all regions:"
716     );
717     txt += "\n\n";
718     for (std::set<Glib::ustring>::const_iterator it = errors.begin();
719     it != errors.end(); ++it)
720     {
721     txt += "-> " + *it + "\n";
722     }
723     txt += "\n";
724     txt += _(
725     "You might also want to check the console for further warnings and "
726     "error messages."
727     );
728 schoenebeck 1225 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
729     msg.run();
730     }
731     }
732     }

  ViewVC Help
Powered by ViewVC