/[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 2844 - (hide annotations) (download)
Sun Sep 20 08:49:40 2015 UTC (8 years, 6 months ago) by persson
File size: 28974 byte(s)
* allow building with gtkmm 2 and G/GDK/GTK_DISABLE_DEPRECATED

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/stock.h>
31     #include <gtkmm/messagedialog.h>
32     #include <gtkmm/dialog.h>
33     #include <gtkmm/comboboxtext.h>
34 persson 1733 #include <gtkmm/spinbutton.h>
35     #include <gtkmm/table.h>
36 schoenebeck 1225
37 persson 1831 #include "global.h"
38 persson 2169 #include "compat.h"
39 persson 1831
40 schoenebeck 1225 // returns a human readable name of the given dimension type
41 schoenebeck 2558 Glib::ustring dimTypeAsString(gig::dimension_t d) {
42 schoenebeck 1225 char buf[32];
43     switch (d) {
44     case gig::dimension_none:
45 persson 1831 return _("None");
46 schoenebeck 1225 case gig::dimension_samplechannel:
47 persson 1831 return _("Sample Channel");
48 schoenebeck 1225 case gig::dimension_layer:
49 persson 1831 return _("Layer");
50 schoenebeck 1225 case gig::dimension_velocity:
51 persson 1831 return _("Velocity");
52 schoenebeck 1225 case gig::dimension_channelaftertouch:
53 persson 1831 return _("Aftertouch");
54 schoenebeck 1225 case gig::dimension_releasetrigger:
55 persson 1831 return _("Release Trigger");
56 schoenebeck 1225 case gig::dimension_keyboard:
57 persson 1831 return _("Keyswitching");
58 schoenebeck 1225 case gig::dimension_roundrobin:
59 persson 1831 return _("Round Robin");
60 schoenebeck 1225 case gig::dimension_random:
61 persson 1831 return _("Random Generator");
62 schoenebeck 1225 case gig::dimension_smartmidi:
63 persson 1831 return _("Smart MIDI");
64 schoenebeck 1225 case gig::dimension_roundrobinkeyboard:
65 persson 1831 return _("Keyboard Round Robin");
66 schoenebeck 1225 case gig::dimension_modwheel:
67 persson 1831 return _("Modulation Wheel");
68 schoenebeck 1225 case gig::dimension_breath:
69 persson 1831 return _("Breath Ctrl.");
70 schoenebeck 1225 case gig::dimension_foot:
71 persson 1831 return _("Foot Ctrl.");
72 schoenebeck 1225 case gig::dimension_portamentotime:
73 persson 1831 return _("Portamento Time Ctrl.");
74 schoenebeck 1225 case gig::dimension_effect1:
75 persson 1831 return _("Effect Ctrl. 1");
76 schoenebeck 1225 case gig::dimension_effect2:
77 persson 1831 return _("Effect Ctrl. 2");
78 schoenebeck 1225 case gig::dimension_genpurpose1:
79 persson 1831 return _("General Purpose Ctrl. 1");
80 schoenebeck 1225 case gig::dimension_genpurpose2:
81 persson 1831 return _("General Purpose Ctrl. 2");
82 schoenebeck 1225 case gig::dimension_genpurpose3:
83 persson 1831 return _("General Purpose Ctrl. 3");
84 schoenebeck 1225 case gig::dimension_genpurpose4:
85 persson 1831 return _("General Purpose Ctrl. 4");
86 schoenebeck 1225 case gig::dimension_sustainpedal:
87 persson 1831 return _("Sustain Pedal");
88 schoenebeck 1225 case gig::dimension_portamento:
89 persson 1831 return _("Portamento Ctrl.");
90 schoenebeck 1225 case gig::dimension_sostenutopedal:
91 persson 1831 return _("Sostenuto Pedal");
92 schoenebeck 1225 case gig::dimension_softpedal:
93 persson 1831 return _("Soft Pedal");
94 schoenebeck 1225 case gig::dimension_genpurpose5:
95 persson 1831 return _("General Purpose Ctrl. 5");
96 schoenebeck 1225 case gig::dimension_genpurpose6:
97 persson 1831 return _("General Purpose Ctrl. 6");
98 schoenebeck 1225 case gig::dimension_genpurpose7:
99 persson 1831 return _("General Purpose Ctrl. 7");
100 schoenebeck 1225 case gig::dimension_genpurpose8:
101 persson 1831 return _("General Purpose Ctrl. 8");
102 schoenebeck 1225 case gig::dimension_effect1depth:
103 persson 1831 return _("Effect 1 Depth");
104 schoenebeck 1225 case gig::dimension_effect2depth:
105 persson 1831 return _("Effect 2 Depth");
106 schoenebeck 1225 case gig::dimension_effect3depth:
107 persson 1831 return _("Effect 3 Depth");
108 schoenebeck 1225 case gig::dimension_effect4depth:
109 persson 1831 return _("Effect 4 Depth");
110 schoenebeck 1225 case gig::dimension_effect5depth:
111 persson 1831 return _("Effect 5 Depth");
112 schoenebeck 1225 default:
113     sprintf(buf, "Unknown Type (0x%x) !!!", d);
114     return buf;
115     }
116     }
117    
118     // returns a human readable description of the given dimension
119     static Glib::ustring __dimDescriptionAsString(gig::dimension_t d) {
120     switch (d) {
121     case gig::dimension_none:
122 persson 1831 return _("Dimension not in use");
123 schoenebeck 1225 case gig::dimension_samplechannel:
124 persson 1831 return _("If used sample has more than one channel (thus is not mono)");
125 schoenebeck 1225 case gig::dimension_layer:
126 persson 1831 return _("For layering of up to 8 instruments (and eventually crossfading of 2 or 4 layers");
127 schoenebeck 1225 case gig::dimension_velocity:
128 persson 1831 return _("Key Velocity (this is the only dimension in gig2 where the ranges can exactly be defined)");
129 schoenebeck 1225 case gig::dimension_channelaftertouch:
130 persson 1831 return _("Channel Key Pressure");
131 schoenebeck 1225 case gig::dimension_releasetrigger:
132 persson 1831 return _("Special dimension for triggering samples on releasing a key");
133 schoenebeck 1225 case gig::dimension_keyboard:
134 persson 1831 return _("Dimension for keyswitching (keyboard)");
135 schoenebeck 1225 case gig::dimension_roundrobin:
136 persson 1831 return _("Different samples triggered each time a note is played, dimension regions selected in sequence");
137 schoenebeck 1225 case gig::dimension_random:
138 persson 1831 return _("Different samples triggered each time a note is played, random order");
139 schoenebeck 1225 case gig::dimension_smartmidi:
140 persson 1831 return _("For MIDI tools like legato and repetition mode");
141 schoenebeck 1225 case gig::dimension_roundrobinkeyboard:
142 persson 1831 return _("Different samples triggered each time a note is played, any key advances the counter");
143 schoenebeck 1225 case gig::dimension_modwheel:
144 persson 1831 return _("MIDI Controller 1");
145 schoenebeck 1225 case gig::dimension_breath:
146 persson 1831 return _("MIDI Controller 2");
147 schoenebeck 1225 case gig::dimension_foot:
148 persson 1831 return _("MIDI Controller 4");
149 schoenebeck 1225 case gig::dimension_portamentotime:
150 persson 1831 return _("MIDI Controller 5");
151 schoenebeck 1225 case gig::dimension_effect1:
152 persson 1831 return _("MIDI Controller 12");
153 schoenebeck 1225 case gig::dimension_effect2:
154 persson 1831 return _("MIDI Controller 13");
155 schoenebeck 1225 case gig::dimension_genpurpose1:
156 persson 1831 return _("Slider, MIDI Controller 16");
157 schoenebeck 1225 case gig::dimension_genpurpose2:
158 persson 1831 return _("Slider, MIDI Controller 17");
159 schoenebeck 1225 case gig::dimension_genpurpose3:
160 persson 1831 return _("Slider, MIDI Controller 18");
161 schoenebeck 1225 case gig::dimension_genpurpose4:
162 persson 1831 return _("Slider, MIDI Controller 19");
163 schoenebeck 1225 case gig::dimension_sustainpedal:
164 persson 1831 return _("MIDI Controller 64");
165 schoenebeck 1225 case gig::dimension_portamento:
166 persson 1831 return _("MIDI Controller 65");
167 schoenebeck 1225 case gig::dimension_sostenutopedal:
168 persson 1831 return _("MIDI Controller 66");
169 schoenebeck 1225 case gig::dimension_softpedal:
170 persson 1831 return _("MIDI Controller 67");
171 schoenebeck 1225 case gig::dimension_genpurpose5:
172 persson 1831 return _("Button, MIDI Controller 80");
173 schoenebeck 1225 case gig::dimension_genpurpose6:
174 persson 1831 return _("Button, MIDI Controller 81");
175 schoenebeck 1225 case gig::dimension_genpurpose7:
176 persson 1831 return _("Button, MIDI Controller 82");
177 schoenebeck 1225 case gig::dimension_genpurpose8:
178 persson 1831 return _("Button, MIDI Controller 83");
179 schoenebeck 1225 case gig::dimension_effect1depth:
180 persson 1831 return _("MIDI Controller 91");
181 schoenebeck 1225 case gig::dimension_effect2depth:
182 persson 1831 return _("MIDI Controller 92");
183 schoenebeck 1225 case gig::dimension_effect3depth:
184 persson 1831 return _("MIDI Controller 93");
185 schoenebeck 1225 case gig::dimension_effect4depth:
186 persson 1831 return _("MIDI Controller 94");
187 schoenebeck 1225 case gig::dimension_effect5depth:
188 persson 1831 return _("MIDI Controller 95");
189 schoenebeck 1225 default:
190 persson 1831 return _("Please report this !!!");
191 schoenebeck 1225 }
192     }
193    
194 schoenebeck 2562 DimTypeCellRenderer::DimTypeCellRenderer() :
195     Glib::ObjectBase(typeid(DimTypeCellRenderer)),
196     Gtk::CellRendererText(),
197     m_propertyDimType(*this, "gigdimension_t", gig::dimension_none),
198     m_propertyUsageCount(*this, "intusagecount", 0),
199     m_propertyTotalRegions(*this, "inttotalregions", 0)
200     {
201     propertyDimType().signal_changed().connect(
202     sigc::mem_fun(*this, &DimTypeCellRenderer::typeChanged)
203     );
204     propertyUsageCount().signal_changed().connect(
205     sigc::mem_fun(*this, &DimTypeCellRenderer::statsChanged)
206     );
207     propertyTotalRegions().signal_changed().connect(
208     sigc::mem_fun(*this, &DimTypeCellRenderer::statsChanged)
209     );
210     }
211    
212     void DimTypeCellRenderer::typeChanged() {
213     gig::dimension_t type = propertyDimType();
214     Glib::ustring s = dimTypeAsString(type);
215     property_text() = s;
216     }
217    
218     void DimTypeCellRenderer::statsChanged() {
219     int usageCount = propertyUsageCount();
220     int totalRegions = propertyTotalRegions();
221     bool bDimensionExistsOnAllRegions = (usageCount == totalRegions);
222     property_foreground() = ((bDimensionExistsOnAllRegions) ? "black" : "gray");
223     }
224    
225     IntSetCellRenderer::IntSetCellRenderer() :
226     Glib::ObjectBase(typeid(IntSetCellRenderer)),
227     Gtk::CellRendererText(),
228     m_propertyValue(*this, "stdintset", std::set<int>())
229     {
230     propertyValue().signal_changed().connect(
231     sigc::mem_fun(*this, &IntSetCellRenderer::valueChanged)
232     );
233     }
234    
235     void IntSetCellRenderer::valueChanged() {
236     Glib::ustring s;
237     std::set<int> v = propertyValue();
238     for (std::set<int>::const_iterator it = v.begin(); it != v.end(); ++it) {
239     s += ToString(*it);
240     if (*it != *v.rbegin()) s += "|";
241     }
242     property_text() = s;
243     property_foreground() = (v.size() > 1) ? "gray" : "black";
244     }
245    
246 schoenebeck 1225 DimensionManager::DimensionManager() :
247 schoenebeck 2562 addButton(Gtk::Stock::ADD), removeButton(Gtk::Stock::REMOVE),
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     //HACK: Prevents that onColumnClicked() gets called multiple times or at times where it is not desired
396     if (ignoreColumnClicked) {
397     ignoreColumnClicked = false;
398     return;
399     }
400    
401     Gtk::TreeModel::Path path;
402     Gtk::TreeViewColumn* focus_column;
403     treeView.get_cursor(path, focus_column);
404     //const int row = path[0];
405     if (focus_column == treeView.get_column(0)) {
406     Gtk::TreeModel::iterator it = treeView.get_model()->get_iter(path);
407     Gtk::TreeModel::Row row = *it;
408     gig::dimension_t oldType = row[tableModel.m_type];
409    
410     Gtk::Dialog dialog(_("Change Dimension"), true /*modal*/);
411     int oldTypeIndex = -1;
412     Glib::RefPtr<Gtk::ListStore> refComboModel = Gtk::ListStore::create(comboModel);
413     for (int i = 0x01, count = 0; i < 0xff; i++) {
414     Glib::ustring sType =
415     dimTypeAsString(static_cast<gig::dimension_t>(i));
416     if (i == oldType) oldTypeIndex = count;
417     if (sType.find("Unknown") != 0) {
418     Gtk::TreeModel::Row row = *(refComboModel->append());
419     row[comboModel.m_type_id] = i;
420     row[comboModel.m_type_name] = sType;
421     count++;
422     }
423     }
424     Gtk::Table table(1, 2);
425     Gtk::Label labelDimType(_("Dimension:"), Gtk::ALIGN_START);
426     Gtk::ComboBox comboDimType;
427     comboDimType.set_model(refComboModel);
428     comboDimType.pack_start(comboModel.m_type_id);
429     comboDimType.pack_start(comboModel.m_type_name);
430     table.attach(labelDimType, 0, 1, 0, 1);
431     table.attach(comboDimType, 1, 2, 0, 1);
432     dialog.get_vbox()->pack_start(table);
433    
434     dialog.add_button(Gtk::Stock::OK, 0);
435     dialog.add_button(Gtk::Stock::CANCEL, 1);
436     dialog.show_all_children();
437    
438     comboDimType.set_active(oldTypeIndex);
439    
440     if (!dialog.run()) { // OK selected ...
441     Gtk::TreeModel::iterator iterType = comboDimType.get_active();
442     if (!iterType) return;
443     Gtk::TreeModel::Row rowType = *iterType;
444     if (!rowType) return;
445     int iTypeID = rowType[comboModel.m_type_id];
446     gig::dimension_t newType = static_cast<gig::dimension_t>(iTypeID);
447     if (newType == oldType) return;
448     //printf("change 0x%x -> 0x%x\n", oldType, newType);
449     ignoreColumnClicked = true;
450    
451     // assemble the list of regions where the selected dimension type
452     // shall be changed
453     std::vector<gig::Region*> vRegions;
454     if (allRegions()) {
455     gig::Instrument* instr = (gig::Instrument*)region->GetParent();
456     for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
457     if (rgn->GetDimensionDefinition(oldType)) vRegions.push_back(rgn);
458     }
459     } else vRegions.push_back(region);
460    
461     std::set<Glib::ustring> errors;
462    
463     for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
464     gig::Region* region = vRegions[iRgn];
465     try {
466     // notify everybody that we're going to update the region
467     region_to_be_changed_signal.emit(region);
468     // change the dimension type on that region
469     region->SetDimensionType(oldType, newType);
470     // let everybody know there was a change
471     region_changed_signal.emit(region);
472     } catch (RIFF::Exception e) {
473     // notify that the changes are over (i.e. to avoid dead locks)
474     region_changed_signal.emit(region);
475     Glib::ustring txt = _("Could not alter dimension: ") + e.Message;
476     if (vRegions.size() == 1) {
477     // show error message directly
478     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
479     msg.run();
480     } else {
481     // remember error, they are shown after all regions have been processed
482     errors.insert(txt);
483     }
484     }
485     }
486     // update all GUI elements
487     refreshManager();
488    
489     if (!errors.empty()) {
490     Glib::ustring txt = _(
491     "The following errors occurred while trying to change the dimension type on all regions:"
492     );
493     txt += "\n\n";
494     for (std::set<Glib::ustring>::const_iterator it = errors.begin();
495     it != errors.end(); ++it)
496     {
497     txt += "-> " + *it + "\n";
498     }
499     txt += "\n";
500     txt += _(
501     "You might also want to check the console for further warnings and "
502     "error messages."
503     );
504     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
505     msg.run();
506     }
507     }
508     }
509     }
510    
511 schoenebeck 1225 void DimensionManager::addDimension() {
512 schoenebeck 2562 Gtk::Dialog dialog(_("New Dimension"), true /*modal*/);
513     // add dimension type combo box to the dialog
514     Glib::RefPtr<Gtk::ListStore> refComboModel = Gtk::ListStore::create(comboModel);
515     for (int i = 0x01; i < 0xff; i++) {
516     Glib::ustring sType =
517     dimTypeAsString(static_cast<gig::dimension_t>(i));
518     if (sType.find("Unknown") != 0) {
519     Gtk::TreeModel::Row row = *(refComboModel->append());
520     row[comboModel.m_type_id] = i;
521     row[comboModel.m_type_name] = sType;
522 schoenebeck 1225 }
523 schoenebeck 2562 }
524     Gtk::Table table(2, 2);
525     Gtk::Label labelDimType(_("Dimension:"), Gtk::ALIGN_START);
526     Gtk::ComboBox comboDimType;
527     comboDimType.set_model(refComboModel);
528     comboDimType.pack_start(comboModel.m_type_id);
529     comboDimType.pack_start(comboModel.m_type_name);
530     Gtk::Label labelZones(_("Zones:"), Gtk::ALIGN_START);
531     table.attach(labelDimType, 0, 1, 0, 1);
532     table.attach(comboDimType, 1, 2, 0, 1);
533     table.attach(labelZones, 0, 1, 1, 2);
534     dialog.get_vbox()->pack_start(table);
535 persson 1733
536 schoenebeck 2562 // number of zones: use a combo box with fix values for gig
537     // v2 and a spin button for v3
538     Gtk::ComboBoxText comboZones;
539     Gtk::SpinButton spinZones;
540     bool version2 = false;
541     if (region) {
542     gig::File* file = (gig::File*)region->GetParent()->GetParent();
543     version2 = file->pVersion && file->pVersion->major == 2;
544     }
545     if (version2) {
546     for (int i = 1; i <= 5; i++) {
547     char buf[3];
548     sprintf(buf, "%d", 1 << i);
549 persson 2507 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
550 schoenebeck 2562 comboZones.append_text(buf);
551 persson 2169 #else
552 schoenebeck 2562 comboZones.append(buf);
553 persson 2169 #endif
554 schoenebeck 2562 }
555     table.attach(comboZones, 1, 2, 1, 2);
556     } else {
557     spinZones.set_increments(1, 8);
558     spinZones.set_numeric(true);
559     spinZones.set_range(2, 128);
560     spinZones.set_value(2);
561     table.attach(spinZones, 1, 2, 1, 2);
562     }
563    
564     dialog.add_button(Gtk::Stock::OK, 0);
565     dialog.add_button(Gtk::Stock::CANCEL, 1);
566     dialog.show_all_children();
567    
568     if (!dialog.run()) { // OK selected ...
569     Gtk::TreeModel::iterator iterType = comboDimType.get_active();
570     if (!iterType) return;
571     Gtk::TreeModel::Row rowType = *iterType;
572     if (!rowType) return;
573     int iTypeID = rowType[comboModel.m_type_id];
574     gig::dimension_t type = static_cast<gig::dimension_t>(iTypeID);
575     gig::dimension_def_t dim;
576     dim.dimension = type;
577    
578     if (version2) {
579     if (comboZones.get_active_row_number() < 0) return;
580     dim.bits = comboZones.get_active_row_number() + 1;
581     dim.zones = 1 << dim.bits;
582 persson 1733 } else {
583 schoenebeck 2562 dim.zones = spinZones.get_value_as_int();
584     dim.bits = zoneCountToBits(dim.zones);
585 persson 1733 }
586    
587 schoenebeck 2562 // assemble the list of regions where the selected dimension shall be
588     // added to
589     std::vector<gig::Region*> vRegions;
590     if (allRegions()) {
591     gig::Instrument* instr = (gig::Instrument*)region->GetParent();
592     for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
593     if (!rgn->GetDimensionDefinition(type)) vRegions.push_back(rgn);
594     }
595     } else vRegions.push_back(region);
596    
597     std::set<Glib::ustring> errors;
598 persson 1733
599 schoenebeck 2562 for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
600     gig::Region* region = vRegions[iRgn];
601     try {
602     printf(
603     "Adding dimension (type=0x%x, bits=%d, zones=%d)\n",
604     dim.dimension, dim.bits, dim.zones
605     );
606     // notify everybody that we're going to update the region
607     region_to_be_changed_signal.emit(region);
608     // add the new dimension to the region
609     // (implicitly creates new dimension regions)
610     region->AddDimension(&dim);
611     // let everybody know there was a change
612     region_changed_signal.emit(region);
613     } catch (RIFF::Exception e) {
614     // notify that the changes are over (i.e. to avoid dead locks)
615     region_changed_signal.emit(region);
616     Glib::ustring txt = _("Could not add dimension: ") + e.Message;
617     if (vRegions.size() == 1) {
618     // show error message directly
619     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
620     msg.run();
621     } else {
622     // remember error, they are shown after all regions have been processed
623     errors.insert(txt);
624     }
625     }
626     }
627     // update all GUI elements
628     refreshManager();
629 persson 1733
630 schoenebeck 2562 if (!errors.empty()) {
631     Glib::ustring txt = _(
632     "The following errors occurred while trying to create the dimension on all regions:"
633     );
634     txt += "\n\n";
635     for (std::set<Glib::ustring>::const_iterator it = errors.begin();
636     it != errors.end(); ++it)
637     {
638     txt += "-> " + *it + "\n";
639 persson 1733 }
640 schoenebeck 2562 txt += "\n";
641     txt += _(
642     "You might also want to check the console for further warnings and "
643     "error messages."
644 schoenebeck 1225 );
645 schoenebeck 2562 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
646     msg.run();
647 schoenebeck 1225 }
648     }
649     }
650    
651 schoenebeck 2562 void DimensionManager::removeDimension() {
652 schoenebeck 1225 Glib::RefPtr<Gtk::TreeSelection> sel = treeView.get_selection();
653     Gtk::TreeModel::iterator it = sel->get_selected();
654     if (it) {
655 schoenebeck 2562 Gtk::TreeModel::Row row = *it;
656     gig::dimension_t type = row[tableModel.m_type];
657    
658     // assemble the list of regions where the selected dimension shall be
659     // added to
660     std::vector<gig::Region*> vRegions;
661     if (allRegions()) {
662     gig::Instrument* instr = (gig::Instrument*)region->GetParent();
663     for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
664     if (rgn->GetDimensionDefinition(type)) vRegions.push_back(rgn);
665     }
666     } else vRegions.push_back(region);
667    
668     std::set<Glib::ustring> errors;
669    
670     for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
671     gig::Region* region = vRegions[iRgn];
672     gig::dimension_def_t* dim = region->GetDimensionDefinition(type);
673     try {
674     // notify everybody that we're going to update the region
675     region_to_be_changed_signal.emit(region);
676     // remove selected dimension
677     region->DeleteDimension(dim);
678     // let everybody know there was a change
679     region_changed_signal.emit(region);
680     } catch (RIFF::Exception e) {
681     // notify that the changes are over (i.e. to avoid dead locks)
682     region_changed_signal.emit(region);
683     Glib::ustring txt = _("Could not remove dimension: ") + e.Message;
684     if (vRegions.size() == 1) {
685     // show error message directly
686     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
687     msg.run();
688     } else {
689     // remember error, they are shown after all regions have been processed
690     errors.insert(txt);
691     }
692     }
693     }
694     // update all GUI elements
695     refreshManager();
696    
697     if (!errors.empty()) {
698     Glib::ustring txt = _(
699     "The following errors occurred while trying to remove the dimension from all regions:"
700     );
701     txt += "\n\n";
702     for (std::set<Glib::ustring>::const_iterator it = errors.begin();
703     it != errors.end(); ++it)
704     {
705     txt += "-> " + *it + "\n";
706     }
707     txt += "\n";
708     txt += _(
709     "You might also want to check the console for further warnings and "
710     "error messages."
711     );
712 schoenebeck 1225 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
713     msg.run();
714     }
715     }
716     }

  ViewVC Help
Powered by ViewVC