/[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 2919 - (hide annotations) (download)
Wed May 18 11:37:31 2016 UTC (7 years, 10 months ago) by schoenebeck
File size: 29353 byte(s)
* Fixed crash after changing a dimension type with the dimension manager
  dialog.
* Bumped version (1.0.0.svn15).

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 2919 // prevents app to crash if this dialog is closed
405     if (!get_visible())
406     return;
407 schoenebeck 2641
408     Gtk::TreeModel::Path path;
409     Gtk::TreeViewColumn* focus_column;
410     treeView.get_cursor(path, focus_column);
411     //const int row = path[0];
412     if (focus_column == treeView.get_column(0)) {
413     Gtk::TreeModel::iterator it = treeView.get_model()->get_iter(path);
414     Gtk::TreeModel::Row row = *it;
415     gig::dimension_t oldType = row[tableModel.m_type];
416    
417     Gtk::Dialog dialog(_("Change Dimension"), true /*modal*/);
418     int oldTypeIndex = -1;
419     Glib::RefPtr<Gtk::ListStore> refComboModel = Gtk::ListStore::create(comboModel);
420     for (int i = 0x01, count = 0; i < 0xff; i++) {
421     Glib::ustring sType =
422     dimTypeAsString(static_cast<gig::dimension_t>(i));
423     if (i == oldType) oldTypeIndex = count;
424     if (sType.find("Unknown") != 0) {
425     Gtk::TreeModel::Row row = *(refComboModel->append());
426     row[comboModel.m_type_id] = i;
427     row[comboModel.m_type_name] = sType;
428     count++;
429     }
430     }
431     Gtk::Table table(1, 2);
432     Gtk::Label labelDimType(_("Dimension:"), Gtk::ALIGN_START);
433     Gtk::ComboBox comboDimType;
434     comboDimType.set_model(refComboModel);
435     comboDimType.pack_start(comboModel.m_type_id);
436     comboDimType.pack_start(comboModel.m_type_name);
437     table.attach(labelDimType, 0, 1, 0, 1);
438     table.attach(comboDimType, 1, 2, 0, 1);
439     dialog.get_vbox()->pack_start(table);
440    
441 persson 2845 dialog.add_button(_("_OK"), 0);
442     dialog.add_button(_("_Cancel"), 1);
443 schoenebeck 2641 dialog.show_all_children();
444    
445     comboDimType.set_active(oldTypeIndex);
446    
447     if (!dialog.run()) { // OK selected ...
448 schoenebeck 2919 ignoreColumnClicked = true;
449 schoenebeck 2641 Gtk::TreeModel::iterator iterType = comboDimType.get_active();
450     if (!iterType) return;
451     Gtk::TreeModel::Row rowType = *iterType;
452     if (!rowType) return;
453     int iTypeID = rowType[comboModel.m_type_id];
454     gig::dimension_t newType = static_cast<gig::dimension_t>(iTypeID);
455     if (newType == oldType) return;
456     //printf("change 0x%x -> 0x%x\n", oldType, newType);
457    
458     // assemble the list of regions where the selected dimension type
459     // shall be changed
460     std::vector<gig::Region*> vRegions;
461     if (allRegions()) {
462     gig::Instrument* instr = (gig::Instrument*)region->GetParent();
463     for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
464     if (rgn->GetDimensionDefinition(oldType)) vRegions.push_back(rgn);
465     }
466     } else vRegions.push_back(region);
467    
468     std::set<Glib::ustring> errors;
469    
470     for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
471     gig::Region* region = vRegions[iRgn];
472     try {
473     // notify everybody that we're going to update the region
474     region_to_be_changed_signal.emit(region);
475     // change the dimension type on that region
476     region->SetDimensionType(oldType, newType);
477     // let everybody know there was a change
478     region_changed_signal.emit(region);
479     } catch (RIFF::Exception e) {
480     // notify that the changes are over (i.e. to avoid dead locks)
481     region_changed_signal.emit(region);
482     Glib::ustring txt = _("Could not alter dimension: ") + e.Message;
483     if (vRegions.size() == 1) {
484     // show error message directly
485     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
486     msg.run();
487     } else {
488     // remember error, they are shown after all regions have been processed
489     errors.insert(txt);
490     }
491     }
492     }
493     // update all GUI elements
494     refreshManager();
495    
496     if (!errors.empty()) {
497     Glib::ustring txt = _(
498     "The following errors occurred while trying to change the dimension type on all regions:"
499     );
500     txt += "\n\n";
501     for (std::set<Glib::ustring>::const_iterator it = errors.begin();
502     it != errors.end(); ++it)
503     {
504     txt += "-> " + *it + "\n";
505     }
506     txt += "\n";
507     txt += _(
508     "You might also want to check the console for further warnings and "
509     "error messages."
510     );
511     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
512     msg.run();
513     }
514     }
515     }
516     }
517    
518 schoenebeck 1225 void DimensionManager::addDimension() {
519 schoenebeck 2562 Gtk::Dialog dialog(_("New Dimension"), true /*modal*/);
520     // add dimension type combo box to the dialog
521     Glib::RefPtr<Gtk::ListStore> refComboModel = Gtk::ListStore::create(comboModel);
522     for (int i = 0x01; i < 0xff; i++) {
523     Glib::ustring sType =
524     dimTypeAsString(static_cast<gig::dimension_t>(i));
525     if (sType.find("Unknown") != 0) {
526     Gtk::TreeModel::Row row = *(refComboModel->append());
527     row[comboModel.m_type_id] = i;
528     row[comboModel.m_type_name] = sType;
529 schoenebeck 1225 }
530 schoenebeck 2562 }
531     Gtk::Table table(2, 2);
532     Gtk::Label labelDimType(_("Dimension:"), Gtk::ALIGN_START);
533     Gtk::ComboBox comboDimType;
534     comboDimType.set_model(refComboModel);
535     comboDimType.pack_start(comboModel.m_type_id);
536     comboDimType.pack_start(comboModel.m_type_name);
537     Gtk::Label labelZones(_("Zones:"), Gtk::ALIGN_START);
538     table.attach(labelDimType, 0, 1, 0, 1);
539     table.attach(comboDimType, 1, 2, 0, 1);
540     table.attach(labelZones, 0, 1, 1, 2);
541     dialog.get_vbox()->pack_start(table);
542 persson 1733
543 schoenebeck 2562 // number of zones: use a combo box with fix values for gig
544     // v2 and a spin button for v3
545     Gtk::ComboBoxText comboZones;
546     Gtk::SpinButton spinZones;
547     bool version2 = false;
548     if (region) {
549     gig::File* file = (gig::File*)region->GetParent()->GetParent();
550     version2 = file->pVersion && file->pVersion->major == 2;
551     }
552     if (version2) {
553     for (int i = 1; i <= 5; i++) {
554     char buf[3];
555     sprintf(buf, "%d", 1 << i);
556 persson 2507 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
557 schoenebeck 2562 comboZones.append_text(buf);
558 persson 2169 #else
559 schoenebeck 2562 comboZones.append(buf);
560 persson 2169 #endif
561 schoenebeck 2562 }
562     table.attach(comboZones, 1, 2, 1, 2);
563     } else {
564     spinZones.set_increments(1, 8);
565     spinZones.set_numeric(true);
566     spinZones.set_range(2, 128);
567     spinZones.set_value(2);
568     table.attach(spinZones, 1, 2, 1, 2);
569     }
570    
571 persson 2845 dialog.add_button(_("_OK"), 0);
572     dialog.add_button(_("_Cancel"), 1);
573 schoenebeck 2562 dialog.show_all_children();
574    
575     if (!dialog.run()) { // OK selected ...
576     Gtk::TreeModel::iterator iterType = comboDimType.get_active();
577     if (!iterType) return;
578     Gtk::TreeModel::Row rowType = *iterType;
579     if (!rowType) return;
580     int iTypeID = rowType[comboModel.m_type_id];
581     gig::dimension_t type = static_cast<gig::dimension_t>(iTypeID);
582     gig::dimension_def_t dim;
583     dim.dimension = type;
584    
585     if (version2) {
586     if (comboZones.get_active_row_number() < 0) return;
587     dim.bits = comboZones.get_active_row_number() + 1;
588     dim.zones = 1 << dim.bits;
589 persson 1733 } else {
590 schoenebeck 2562 dim.zones = spinZones.get_value_as_int();
591     dim.bits = zoneCountToBits(dim.zones);
592 persson 1733 }
593    
594 schoenebeck 2562 // assemble the list of regions where the selected dimension shall be
595     // added to
596     std::vector<gig::Region*> vRegions;
597     if (allRegions()) {
598     gig::Instrument* instr = (gig::Instrument*)region->GetParent();
599     for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
600     if (!rgn->GetDimensionDefinition(type)) vRegions.push_back(rgn);
601     }
602     } else vRegions.push_back(region);
603    
604     std::set<Glib::ustring> errors;
605 persson 1733
606 schoenebeck 2562 for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
607     gig::Region* region = vRegions[iRgn];
608     try {
609     printf(
610     "Adding dimension (type=0x%x, bits=%d, zones=%d)\n",
611     dim.dimension, dim.bits, dim.zones
612     );
613     // notify everybody that we're going to update the region
614     region_to_be_changed_signal.emit(region);
615     // add the new dimension to the region
616     // (implicitly creates new dimension regions)
617     region->AddDimension(&dim);
618     // let everybody know there was a change
619     region_changed_signal.emit(region);
620     } catch (RIFF::Exception e) {
621     // notify that the changes are over (i.e. to avoid dead locks)
622     region_changed_signal.emit(region);
623     Glib::ustring txt = _("Could not add dimension: ") + e.Message;
624     if (vRegions.size() == 1) {
625     // show error message directly
626     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
627     msg.run();
628     } else {
629     // remember error, they are shown after all regions have been processed
630     errors.insert(txt);
631     }
632     }
633     }
634     // update all GUI elements
635     refreshManager();
636 persson 1733
637 schoenebeck 2562 if (!errors.empty()) {
638     Glib::ustring txt = _(
639     "The following errors occurred while trying to create the dimension on all regions:"
640     );
641     txt += "\n\n";
642     for (std::set<Glib::ustring>::const_iterator it = errors.begin();
643     it != errors.end(); ++it)
644     {
645     txt += "-> " + *it + "\n";
646 persson 1733 }
647 schoenebeck 2562 txt += "\n";
648     txt += _(
649     "You might also want to check the console for further warnings and "
650     "error messages."
651 schoenebeck 1225 );
652 schoenebeck 2562 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
653     msg.run();
654 schoenebeck 1225 }
655     }
656     }
657    
658 schoenebeck 2562 void DimensionManager::removeDimension() {
659 schoenebeck 1225 Glib::RefPtr<Gtk::TreeSelection> sel = treeView.get_selection();
660     Gtk::TreeModel::iterator it = sel->get_selected();
661     if (it) {
662 schoenebeck 2562 Gtk::TreeModel::Row row = *it;
663     gig::dimension_t type = row[tableModel.m_type];
664    
665     // assemble the list of regions where the selected dimension shall be
666     // added to
667     std::vector<gig::Region*> vRegions;
668     if (allRegions()) {
669     gig::Instrument* instr = (gig::Instrument*)region->GetParent();
670     for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
671     if (rgn->GetDimensionDefinition(type)) vRegions.push_back(rgn);
672     }
673     } else vRegions.push_back(region);
674    
675     std::set<Glib::ustring> errors;
676    
677     for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
678     gig::Region* region = vRegions[iRgn];
679     gig::dimension_def_t* dim = region->GetDimensionDefinition(type);
680     try {
681     // notify everybody that we're going to update the region
682     region_to_be_changed_signal.emit(region);
683     // remove selected dimension
684     region->DeleteDimension(dim);
685     // let everybody know there was a change
686     region_changed_signal.emit(region);
687     } catch (RIFF::Exception e) {
688     // notify that the changes are over (i.e. to avoid dead locks)
689     region_changed_signal.emit(region);
690     Glib::ustring txt = _("Could not remove dimension: ") + e.Message;
691     if (vRegions.size() == 1) {
692     // show error message directly
693     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
694     msg.run();
695     } else {
696     // remember error, they are shown after all regions have been processed
697     errors.insert(txt);
698     }
699     }
700     }
701     // update all GUI elements
702     refreshManager();
703    
704     if (!errors.empty()) {
705     Glib::ustring txt = _(
706     "The following errors occurred while trying to remove the dimension from all regions:"
707     );
708     txt += "\n\n";
709     for (std::set<Glib::ustring>::const_iterator it = errors.begin();
710     it != errors.end(); ++it)
711     {
712     txt += "-> " + *it + "\n";
713     }
714     txt += "\n";
715     txt += _(
716     "You might also want to check the console for further warnings and "
717     "error messages."
718     );
719 schoenebeck 1225 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
720     msg.run();
721     }
722     }
723     }

  ViewVC Help
Powered by ViewVC