1 |
/* |
/* |
2 |
* Copyright (C) 2006-2014 Andreas Persson |
* Copyright (C) 2006-2017 Andreas Persson |
3 |
* |
* |
4 |
* This program is free software; you can redistribute it and/or |
* This program is free software; you can redistribute it and/or |
5 |
* modify it under the terms of the GNU General Public License as |
* modify it under the terms of the GNU General Public License as |
17 |
* 02110-1301 USA. |
* 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" |
#include "dimensionmanager.h" |
29 |
|
|
30 |
#include <gtkmm/stock.h> |
#if HAS_GTKMM_STOCK |
31 |
|
# include <gtkmm/stock.h> |
32 |
|
#endif |
33 |
#include <gtkmm/messagedialog.h> |
#include <gtkmm/messagedialog.h> |
34 |
#include <gtkmm/dialog.h> |
#include <gtkmm/dialog.h> |
35 |
#include <gtkmm/comboboxtext.h> |
#include <gtkmm/comboboxtext.h> |
36 |
#include <gtkmm/spinbutton.h> |
#include <gtkmm/spinbutton.h> |
37 |
#include <gtkmm/table.h> |
#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" |
#include "global.h" |
45 |
#include "compat.h" |
#include "compat.h" |
251 |
} |
} |
252 |
|
|
253 |
DimensionManager::DimensionManager() : |
DimensionManager::DimensionManager() : |
254 |
addButton(Gtk::Stock::ADD), removeButton(Gtk::Stock::REMOVE), |
#if HAS_GTKMM_STOCK |
255 |
allRegionsCheckBox(_("All Regions")) |
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")); |
set_title(_("Dimensions of selected Region")); |
275 |
add(vbox); |
add(vbox); |
276 |
scrolledWindow.add(treeView); |
scrolledWindow.add(treeView); |
278 |
scrolledWindow.show(); |
scrolledWindow.show(); |
279 |
vbox.pack_start(buttonBox, Gtk::PACK_SHRINK); |
vbox.pack_start(buttonBox, Gtk::PACK_SHRINK); |
280 |
buttonBox.set_layout(Gtk::BUTTONBOX_END); |
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); |
buttonBox.set_border_width(5); |
285 |
|
#endif |
286 |
buttonBox.show(); |
buttonBox.show(); |
287 |
buttonBox.pack_start(allRegionsCheckBox, Gtk::PACK_EXPAND_PADDING); |
buttonBox.pack_start(allRegionsCheckBox, Gtk::PACK_EXPAND_PADDING); |
288 |
buttonBox.pack_start(addButton, Gtk::PACK_SHRINK); |
buttonBox.pack_start(addButton, Gtk::PACK_SHRINK); |
307 |
treeView.get_column(2)->add_attribute(m_cellRendererIntSet.propertyValue(), tableModel.m_zones); |
treeView.get_column(2)->add_attribute(m_cellRendererIntSet.propertyValue(), tableModel.m_zones); |
308 |
treeView.show(); |
treeView.show(); |
309 |
|
|
310 |
|
treeView.signal_cursor_changed().connect( |
311 |
|
sigc::mem_fun(*this, &DimensionManager::onColumnClicked) |
312 |
|
); |
313 |
|
|
314 |
addButton.signal_clicked().connect( |
addButton.signal_clicked().connect( |
315 |
sigc::mem_fun(*this, &DimensionManager::addDimension) |
sigc::mem_fun(*this, &DimensionManager::addDimension) |
316 |
); |
); |
322 |
sigc::mem_fun(*this, &DimensionManager::onAllRegionsCheckBoxToggled) |
sigc::mem_fun(*this, &DimensionManager::onAllRegionsCheckBoxToggled) |
323 |
); |
); |
324 |
|
|
325 |
|
#if HAS_GTKMM_SHOW_ALL_CHILDREN |
326 |
show_all_children(); |
show_all_children(); |
327 |
|
#endif |
|
resize(460,300); |
|
328 |
} |
} |
329 |
|
|
330 |
bool DimensionManager::allRegions() const { |
bool DimensionManager::allRegions() const { |
353 |
}; |
}; |
354 |
typedef std::map<gig::dimension_t, _DimDef> _Dimensions; |
typedef std::map<gig::dimension_t, _DimDef> _Dimensions; |
355 |
|
|
356 |
// update all GUI elements according to current gig::Region informations |
// update all GUI elements according to current gig::Region information |
357 |
void DimensionManager::refreshManager() { |
void DimensionManager::refreshManager() { |
358 |
set_sensitive(false); |
set_sensitive(false); |
359 |
refTableModel->clear(); |
refTableModel->clear(); |
402 |
} |
} |
403 |
|
|
404 |
void DimensionManager::show(gig::Region* region) { |
void DimensionManager::show(gig::Region* region) { |
405 |
|
ignoreColumnClicked = true; |
406 |
this->region = region; |
this->region = region; |
407 |
refreshManager(); |
refreshManager(); |
408 |
Gtk::Window::show(); |
Gtk::Window::show(); |
409 |
deiconify(); |
deiconify(); |
410 |
|
ignoreColumnClicked = false; |
411 |
} |
} |
412 |
|
|
413 |
void DimensionManager::set_region(gig::Region* region) { |
void DimensionManager::set_region(gig::Region* region) { |
414 |
|
ignoreColumnClicked = true; |
415 |
this->region = region; |
this->region = region; |
416 |
refreshManager(); |
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() { |
void DimensionManager::addDimension() { |
582 |
row[comboModel.m_type_name] = sType; |
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); |
Gtk::Table table(2, 2); |
589 |
|
#endif |
590 |
Gtk::Label labelDimType(_("Dimension:"), Gtk::ALIGN_START); |
Gtk::Label labelDimType(_("Dimension:"), Gtk::ALIGN_START); |
591 |
Gtk::ComboBox comboDimType; |
Gtk::ComboBox comboDimType; |
592 |
comboDimType.set_model(refComboModel); |
comboDimType.set_model(refComboModel); |
593 |
comboDimType.pack_start(comboModel.m_type_id); |
comboDimType.pack_start(comboModel.m_type_id); |
594 |
comboDimType.pack_start(comboModel.m_type_name); |
comboDimType.pack_start(comboModel.m_type_name); |
595 |
Gtk::Label labelZones(_("Zones:"), Gtk::ALIGN_START); |
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); |
table.attach(labelDimType, 0, 1, 0, 1); |
602 |
table.attach(comboDimType, 1, 2, 0, 1); |
table.attach(comboDimType, 1, 2, 0, 1); |
603 |
table.attach(labelZones, 0, 1, 1, 2); |
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); |
dialog.get_vbox()->pack_start(table); |
610 |
|
#endif |
611 |
|
|
612 |
// number of zones: use a combo box with fix values for gig |
// number of zones: use a combo box with fix values for gig |
613 |
// v2 and a spin button for v3 |
// v2 and a spin button for v3 |
637 |
table.attach(spinZones, 1, 2, 1, 2); |
table.attach(spinZones, 1, 2, 1, 2); |
638 |
} |
} |
639 |
|
|
640 |
|
#if HAS_GTKMM_STOCK |
641 |
dialog.add_button(Gtk::Stock::OK, 0); |
dialog.add_button(Gtk::Stock::OK, 0); |
642 |
dialog.add_button(Gtk::Stock::CANCEL, 1); |
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(); |
dialog.show_all_children(); |
649 |
|
#endif |
650 |
|
|
651 |
if (!dialog.run()) { // OK selected ... |
if (!dialog.run()) { // OK selected ... |
652 |
Gtk::TreeModel::iterator iterType = comboDimType.get_active(); |
Gtk::TreeModel::iterator iterType = comboDimType.get_active(); |