/[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 3409 - (show annotations) (download)
Tue Jan 23 16:30:56 2018 UTC (6 years, 2 months ago) by schoenebeck
File size: 31942 byte(s)
* Added new main menu item "View" -> "Tooltips for Beginners" which allows
  to disable tooltips intended for newbies only (default: on).
* Bumped version (1.1.0.svn3).

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 Settings::singleton()->showTooltips.get_proxy().signal_changed().connect(
330 sigc::mem_fun(*this, &DimensionManager::on_show_tooltips_changed)
331 );
332 on_show_tooltips_changed();
333 }
334
335 void DimensionManager::on_show_tooltips_changed() {
336 const bool b = Settings::singleton()->showTooltips;
337
338 treeView.set_has_tooltip(b);
339 allRegionsCheckBox.set_has_tooltip(b);
340
341 set_has_tooltip(b);
342 }
343
344 bool DimensionManager::allRegions() const {
345 return allRegionsCheckBox.get_active();
346 }
347
348 void DimensionManager::onAllRegionsCheckBoxToggled() {
349 set_title(
350 allRegions() ? _("Dimensions of all Regions") : _("Dimensions of selected Region")
351 );
352 treeView.set_tooltip_text(
353 allRegions()
354 ? _("Dimensions and numbers in gray indicates a difference among the individual regions.")
355 : _("You are currently only viewing dimensions of the currently selected region.")
356 );
357 refreshManager();
358 }
359
360 // following two data types are just used in DimensionManager::refresManager(),
361 // due to the maps template nature however, they must be declared at global
362 // space to avoid compilation errors
363 struct _DimDef {
364 std::set<int> bits;
365 std::set<int> zones;
366 int usageCount;
367 };
368 typedef std::map<gig::dimension_t, _DimDef> _Dimensions;
369
370 // update all GUI elements according to current gig::Region information
371 void DimensionManager::refreshManager() {
372 set_sensitive(false);
373 refTableModel->clear();
374 if (allRegions()) {
375 if (region) {
376 _Dimensions dims;
377 gig::Instrument* instr = (gig::Instrument*)region->GetParent();
378 int iRegionsCount = 0;
379 for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion(), ++iRegionsCount) {
380 for (uint i = 0; i < rgn->Dimensions; i++) {
381 gig::dimension_def_t* dim = &rgn->pDimensionDefinitions[i];
382 dims[dim->dimension].bits.insert(dim->bits);
383 dims[dim->dimension].zones.insert(dim->zones);
384 dims[dim->dimension].usageCount++;
385 }
386 }
387 for (_Dimensions::const_iterator it = dims.begin(); it != dims.end(); ++it) {
388 Gtk::TreeModel::Row row = *(refTableModel->append());
389 row[tableModel.m_type] = it->first;
390 row[tableModel.m_bits] = it->second.bits;
391 row[tableModel.m_zones] = it->second.zones;
392 row[tableModel.m_description] = __dimDescriptionAsString(it->first);
393 row[tableModel.m_usageCount] = it->second.usageCount;
394 row[tableModel.m_totalRegions] = iRegionsCount;
395 }
396 }
397 } else {
398 if (region) {
399 for (uint i = 0; i < region->Dimensions; i++) {
400 gig::dimension_def_t* dim = &region->pDimensionDefinitions[i];
401 Gtk::TreeModel::Row row = *(refTableModel->append());
402 std::set<int> vBits;
403 vBits.insert(dim->bits);
404 row[tableModel.m_bits] = vBits;
405 std::set<int> vZones;
406 vZones.insert(dim->zones);
407 row[tableModel.m_zones] = vZones;
408 row[tableModel.m_description] = __dimDescriptionAsString(dim->dimension);
409 row[tableModel.m_type] = dim->dimension;
410 row[tableModel.m_usageCount] = 1;
411 row[tableModel.m_totalRegions] = 1;
412 }
413 }
414 }
415 set_sensitive(region);
416 }
417
418 void DimensionManager::show(gig::Region* region) {
419 ignoreColumnClicked = true;
420 this->region = region;
421 refreshManager();
422 Gtk::Window::show();
423 deiconify();
424 ignoreColumnClicked = false;
425 }
426
427 void DimensionManager::set_region(gig::Region* region) {
428 ignoreColumnClicked = true;
429 this->region = region;
430 refreshManager();
431 ignoreColumnClicked = false;
432 }
433
434 void DimensionManager::onColumnClicked() {
435 printf("DimensionManager::onColumnClicked()\n");
436
437 //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 !
438
439 //HACK: Prevents that onColumnClicked() gets called multiple times or at times where it is not desired
440 if (ignoreColumnClicked) {
441 ignoreColumnClicked = false;
442 return;
443 }
444 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 18) || GTKMM_MAJOR_VERSION > 2
445 // prevents app to crash if this dialog is closed
446 if (!get_visible())
447 return;
448 #else
449 # warning Your GTKMM version is too old; dimension manager dialog might crash when changing a dimension type !
450 #endif
451
452 #if (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION >= 8) || GTKMM_MAJOR_VERSION > 3
453 if (!is_visible()) return;
454 #endif
455
456 Gtk::TreeModel::Path path;
457 Gtk::TreeViewColumn* focus_column;
458 treeView.get_cursor(path, focus_column);
459 //const int row = path[0];
460 if (focus_column == treeView.get_column(0)) {
461 Gtk::TreeModel::iterator it = treeView.get_model()->get_iter(path);
462 if (!it) return;
463 Gtk::TreeModel::Row row = *it;
464 gig::dimension_t oldType = row[tableModel.m_type];
465
466 Gtk::Dialog dialog(_("Change Dimension"), true /*modal*/);
467 int oldTypeIndex = -1;
468 Glib::RefPtr<Gtk::ListStore> refComboModel = Gtk::ListStore::create(comboModel);
469 for (int i = 0x01, count = 0; i < 0xff; i++) {
470 Glib::ustring sType =
471 dimTypeAsString(static_cast<gig::dimension_t>(i));
472 if (i == oldType) oldTypeIndex = count;
473 if (sType.find("Unknown") != 0) {
474 Gtk::TreeModel::Row row = *(refComboModel->append());
475 row[comboModel.m_type_id] = i;
476 row[comboModel.m_type_name] = sType;
477 count++;
478 }
479 }
480 #if USE_GTKMM_GRID
481 Gtk::Grid table;
482 #else
483 Gtk::Table table(1, 2);
484 #endif
485 Gtk::Label labelDimType(_("Dimension:"), Gtk::ALIGN_START);
486 Gtk::ComboBox comboDimType;
487 comboDimType.set_model(refComboModel);
488 comboDimType.pack_start(comboModel.m_type_id);
489 comboDimType.pack_start(comboModel.m_type_name);
490 table.attach(labelDimType, 0, 1, 0, 1);
491 table.attach(comboDimType, 1, 2, 0, 1);
492 #if USE_GTKMM_BOX
493 dialog.get_content_area()->pack_start(table);
494 #else
495 dialog.get_vbox()->pack_start(table);
496 #endif
497
498 #if HAS_GTKMM_STOCK
499 dialog.add_button(Gtk::Stock::OK, 0);
500 dialog.add_button(Gtk::Stock::CANCEL, 1);
501 #else
502 dialog.add_button(_("_OK"), 0);
503 dialog.add_button(_("_Cancel"), 1);
504 #endif
505 #if HAS_GTKMM_SHOW_ALL_CHILDREN
506 dialog.show_all_children();
507 #endif
508
509 comboDimType.set_active(oldTypeIndex);
510
511 if (!dialog.run()) { // OK selected ...
512 ignoreColumnClicked = true;
513 Gtk::TreeModel::iterator iterType = comboDimType.get_active();
514 if (!iterType) return;
515 Gtk::TreeModel::Row rowType = *iterType;
516 if (!rowType) return;
517 int iTypeID = rowType[comboModel.m_type_id];
518 gig::dimension_t newType = static_cast<gig::dimension_t>(iTypeID);
519 if (newType == oldType) return;
520 //printf("change 0x%x -> 0x%x\n", oldType, newType);
521
522 // assemble the list of regions where the selected dimension type
523 // shall be changed
524 std::vector<gig::Region*> vRegions;
525 if (allRegions()) {
526 gig::Instrument* instr = (gig::Instrument*)region->GetParent();
527 for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
528 if (rgn->GetDimensionDefinition(oldType)) vRegions.push_back(rgn);
529 }
530 } else vRegions.push_back(region);
531
532 std::set<Glib::ustring> errors;
533
534 for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
535 gig::Region* region = vRegions[iRgn];
536 try {
537 // notify everybody that we're going to update the region
538 region_to_be_changed_signal.emit(region);
539 // change the dimension type on that region
540 region->SetDimensionType(oldType, newType);
541 // let everybody know there was a change
542 region_changed_signal.emit(region);
543 } catch (RIFF::Exception e) {
544 // notify that the changes are over (i.e. to avoid dead locks)
545 region_changed_signal.emit(region);
546 Glib::ustring txt = _("Could not alter dimension: ") + e.Message;
547 if (vRegions.size() == 1) {
548 // show error message directly
549 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
550 msg.run();
551 } else {
552 // remember error, they are shown after all regions have been processed
553 errors.insert(txt);
554 }
555 }
556 }
557 // update all GUI elements
558 refreshManager();
559
560 if (!errors.empty()) {
561 Glib::ustring txt = _(
562 "The following errors occurred while trying to change the dimension type on all regions:"
563 );
564 txt += "\n\n";
565 for (std::set<Glib::ustring>::const_iterator it = errors.begin();
566 it != errors.end(); ++it)
567 {
568 txt += "-> " + *it + "\n";
569 }
570 txt += "\n";
571 txt += _(
572 "You might also want to check the console for further warnings and "
573 "error messages."
574 );
575 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
576 msg.run();
577 }
578 }
579 } else if (focus_column == treeView.get_column(1) || focus_column == treeView.get_column(2)) {
580 Glib::ustring txt = _("Right-click on a specific dimension zone of the dimension region selector to delete or split that particular dimension zone!");
581 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_INFO);
582 msg.run();
583 }
584 }
585
586 void DimensionManager::addDimension() {
587 Gtk::Dialog dialog(_("New Dimension"), true /*modal*/);
588 // add dimension type combo box to the dialog
589 Glib::RefPtr<Gtk::ListStore> refComboModel = Gtk::ListStore::create(comboModel);
590 for (int i = 0x01; i < 0xff; i++) {
591 Glib::ustring sType =
592 dimTypeAsString(static_cast<gig::dimension_t>(i));
593 if (sType.find("Unknown") != 0) {
594 Gtk::TreeModel::Row row = *(refComboModel->append());
595 row[comboModel.m_type_id] = i;
596 row[comboModel.m_type_name] = sType;
597 }
598 }
599 #if USE_GTKMM_GRID
600 Gtk::Grid table;
601 #else
602 Gtk::Table table(2, 2);
603 #endif
604 Gtk::Label labelDimType(_("Dimension:"), Gtk::ALIGN_START);
605 Gtk::ComboBox comboDimType;
606 comboDimType.set_model(refComboModel);
607 comboDimType.pack_start(comboModel.m_type_id);
608 comboDimType.pack_start(comboModel.m_type_name);
609 Gtk::Label labelZones(_("Zones:"), Gtk::ALIGN_START);
610 #if USE_GTKMM_GRID
611 table.attach(labelDimType, 0, 0);
612 table.attach(comboDimType, 1, 0);
613 table.attach(labelZones, 0, 1);
614 #else
615 table.attach(labelDimType, 0, 1, 0, 1);
616 table.attach(comboDimType, 1, 2, 0, 1);
617 table.attach(labelZones, 0, 1, 1, 2);
618 #endif
619
620 #if USE_GTKMM_BOX
621 dialog.get_content_area()->pack_start(table);
622 #else
623 dialog.get_vbox()->pack_start(table);
624 #endif
625
626 // number of zones: use a combo box with fix values for gig
627 // v2 and a spin button for v3
628 Gtk::ComboBoxText comboZones;
629 Gtk::SpinButton spinZones;
630 bool version2 = false;
631 if (region) {
632 gig::File* file = (gig::File*)region->GetParent()->GetParent();
633 version2 = file->pVersion && file->pVersion->major == 2;
634 }
635 if (version2) {
636 for (int i = 1; i <= 5; i++) {
637 char buf[3];
638 sprintf(buf, "%d", 1 << i);
639 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
640 comboZones.append_text(buf);
641 #else
642 comboZones.append(buf);
643 #endif
644 }
645 table.attach(comboZones, 1, 2, 1, 2);
646 } else {
647 spinZones.set_increments(1, 8);
648 spinZones.set_numeric(true);
649 spinZones.set_range(2, 128);
650 spinZones.set_value(2);
651 table.attach(spinZones, 1, 2, 1, 2);
652 }
653
654 #if HAS_GTKMM_STOCK
655 dialog.add_button(Gtk::Stock::OK, 0);
656 dialog.add_button(Gtk::Stock::CANCEL, 1);
657 #else
658 dialog.add_button(_("_OK"), 0);
659 dialog.add_button(_("_Cancel"), 1);
660 #endif
661 #if HAS_GTKMM_SHOW_ALL_CHILDREN
662 dialog.show_all_children();
663 #endif
664
665 if (!dialog.run()) { // OK selected ...
666 Gtk::TreeModel::iterator iterType = comboDimType.get_active();
667 if (!iterType) return;
668 Gtk::TreeModel::Row rowType = *iterType;
669 if (!rowType) return;
670 int iTypeID = rowType[comboModel.m_type_id];
671 gig::dimension_t type = static_cast<gig::dimension_t>(iTypeID);
672 gig::dimension_def_t dim;
673 dim.dimension = type;
674
675 if (version2) {
676 if (comboZones.get_active_row_number() < 0) return;
677 dim.bits = comboZones.get_active_row_number() + 1;
678 dim.zones = 1 << dim.bits;
679 } else {
680 dim.zones = spinZones.get_value_as_int();
681 dim.bits = zoneCountToBits(dim.zones);
682 }
683
684 // assemble the list of regions where the selected dimension shall be
685 // added to
686 std::vector<gig::Region*> vRegions;
687 if (allRegions()) {
688 gig::Instrument* instr = (gig::Instrument*)region->GetParent();
689 for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
690 if (!rgn->GetDimensionDefinition(type)) vRegions.push_back(rgn);
691 }
692 } else vRegions.push_back(region);
693
694 std::set<Glib::ustring> errors;
695
696 for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
697 gig::Region* region = vRegions[iRgn];
698 try {
699 printf(
700 "Adding dimension (type=0x%x, bits=%d, zones=%d)\n",
701 dim.dimension, dim.bits, dim.zones
702 );
703 // notify everybody that we're going to update the region
704 region_to_be_changed_signal.emit(region);
705 // add the new dimension to the region
706 // (implicitly creates new dimension regions)
707 region->AddDimension(&dim);
708 // let everybody know there was a change
709 region_changed_signal.emit(region);
710 } catch (RIFF::Exception e) {
711 // notify that the changes are over (i.e. to avoid dead locks)
712 region_changed_signal.emit(region);
713 Glib::ustring txt = _("Could not add dimension: ") + e.Message;
714 if (vRegions.size() == 1) {
715 // show error message directly
716 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
717 msg.run();
718 } else {
719 // remember error, they are shown after all regions have been processed
720 errors.insert(txt);
721 }
722 }
723 }
724 // update all GUI elements
725 refreshManager();
726
727 if (!errors.empty()) {
728 Glib::ustring txt = _(
729 "The following errors occurred while trying to create the dimension on all regions:"
730 );
731 txt += "\n\n";
732 for (std::set<Glib::ustring>::const_iterator it = errors.begin();
733 it != errors.end(); ++it)
734 {
735 txt += "-> " + *it + "\n";
736 }
737 txt += "\n";
738 txt += _(
739 "You might also want to check the console for further warnings and "
740 "error messages."
741 );
742 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
743 msg.run();
744 }
745 }
746 }
747
748 void DimensionManager::removeDimension() {
749 Glib::RefPtr<Gtk::TreeSelection> sel = treeView.get_selection();
750 Gtk::TreeModel::iterator it = sel->get_selected();
751 if (it) {
752 Gtk::TreeModel::Row row = *it;
753 gig::dimension_t type = row[tableModel.m_type];
754
755 // assemble the list of regions where the selected dimension shall be
756 // added to
757 std::vector<gig::Region*> vRegions;
758 if (allRegions()) {
759 gig::Instrument* instr = (gig::Instrument*)region->GetParent();
760 for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
761 if (rgn->GetDimensionDefinition(type)) vRegions.push_back(rgn);
762 }
763 } else vRegions.push_back(region);
764
765 std::set<Glib::ustring> errors;
766
767 for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
768 gig::Region* region = vRegions[iRgn];
769 gig::dimension_def_t* dim = region->GetDimensionDefinition(type);
770 try {
771 // notify everybody that we're going to update the region
772 region_to_be_changed_signal.emit(region);
773 // remove selected dimension
774 region->DeleteDimension(dim);
775 // let everybody know there was a change
776 region_changed_signal.emit(region);
777 } catch (RIFF::Exception e) {
778 // notify that the changes are over (i.e. to avoid dead locks)
779 region_changed_signal.emit(region);
780 Glib::ustring txt = _("Could not remove dimension: ") + e.Message;
781 if (vRegions.size() == 1) {
782 // show error message directly
783 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
784 msg.run();
785 } else {
786 // remember error, they are shown after all regions have been processed
787 errors.insert(txt);
788 }
789 }
790 }
791 // update all GUI elements
792 refreshManager();
793
794 if (!errors.empty()) {
795 Glib::ustring txt = _(
796 "The following errors occurred while trying to remove the dimension from all regions:"
797 );
798 txt += "\n\n";
799 for (std::set<Glib::ustring>::const_iterator it = errors.begin();
800 it != errors.end(); ++it)
801 {
802 txt += "-> " + *it + "\n";
803 }
804 txt += "\n";
805 txt += _(
806 "You might also want to check the console for further warnings and "
807 "error messages."
808 );
809 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
810 msg.run();
811 }
812 }
813 }

  ViewVC Help
Powered by ViewVC