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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3473 - (show annotations) (download)
Sat Feb 16 20:35:46 2019 UTC (5 years, 1 month ago) by persson
File size: 31636 byte(s)
- remove G_DISABLE_DEPRECATED hack as glib threads are deprecated now anyway

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

  ViewVC Help
Powered by ViewVC