/[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 3408 - (show annotations) (download)
Fri Jan 19 19:17:41 2018 UTC (6 years, 2 months ago) by schoenebeck
File size: 31537 byte(s)
* Spelling fixes (patch provided by Debian maintainer Jaromír
  Mikeš).

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

  ViewVC Help
Powered by ViewVC