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" |
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() : |
DimensionManager::DimensionManager() : |
254 |
addButton(Gtk::Stock::ADD), removeButton(Gtk::Stock::REMOVE) |
#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")); |
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); |
288 |
buttonBox.pack_start(addButton, Gtk::PACK_SHRINK); |
buttonBox.pack_start(addButton, Gtk::PACK_SHRINK); |
289 |
buttonBox.pack_start(removeButton, Gtk::PACK_SHRINK); |
buttonBox.pack_start(removeButton, Gtk::PACK_SHRINK); |
290 |
addButton.show(); |
addButton.show(); |
291 |
removeButton.show(); |
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 |
// setup the table |
297 |
refTableModel = Gtk::ListStore::create(tableModel); |
refTableModel = Gtk::ListStore::create(tableModel); |
298 |
treeView.set_model(refTableModel); |
treeView.set_model(refTableModel); |
299 |
treeView.append_column(_("Dimension Type"), tableModel.m_dim_type); |
treeView.append_column(_("Dimension Type"), m_cellRendererDimType); |
300 |
treeView.append_column(_("Bits"), tableModel.m_bits); |
treeView.append_column(_("Bits"), m_cellRendererIntSet); |
301 |
treeView.append_column(_("Zones"), tableModel.m_zones); |
treeView.append_column(_("Zones"), m_cellRendererIntSet); |
302 |
treeView.append_column(_("Description"), tableModel.m_description); |
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(); |
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 |
); |
); |
318 |
removeButton.signal_clicked().connect( |
removeButton.signal_clicked().connect( |
319 |
sigc::mem_fun(*this, &DimensionManager::removeDimension) |
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(); |
show_all_children(); |
327 |
|
#endif |
328 |
resize(460,300); |
} |
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 informations |
// update all GUI elements according to current gig::Region informations |
357 |
void DimensionManager::refreshManager() { |
void DimensionManager::refreshManager() { |
358 |
|
set_sensitive(false); |
359 |
refTableModel->clear(); |
refTableModel->clear(); |
360 |
if (region) { |
if (allRegions()) { |
361 |
for (int i = 0; i < region->Dimensions; i++) { |
if (region) { |
362 |
gig::dimension_def_t* dim = ®ion->pDimensionDefinitions[i]; |
_Dimensions dims; |
363 |
Gtk::TreeModel::Row row = *(refTableModel->append()); |
gig::Instrument* instr = (gig::Instrument*)region->GetParent(); |
364 |
row[tableModel.m_dim_type] = dimTypeAsString(dim->dimension); |
int iRegionsCount = 0; |
365 |
row[tableModel.m_bits] = dim->bits; |
for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion(), ++iRegionsCount) { |
366 |
row[tableModel.m_zones] = dim->zones; |
for (uint i = 0; i < rgn->Dimensions; i++) { |
367 |
row[tableModel.m_description] = __dimDescriptionAsString(dim->dimension); |
gig::dimension_def_t* dim = &rgn->pDimensionDefinitions[i]; |
368 |
row[tableModel.m_definition] = dim; |
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 = ®ion->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); |
set_sensitive(region); |
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::addDimension() { |
void DimensionManager::onColumnClicked() { |
421 |
try { |
printf("DimensionManager::onColumnClicked()\n"); |
422 |
Gtk::Dialog dialog(_("New Dimension"), true /*modal*/); |
|
423 |
// add dimension type combo box to the dialog |
//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); |
Glib::RefPtr<Gtk::ListStore> refComboModel = Gtk::ListStore::create(comboModel); |
455 |
for (int i = 0x01; i < 0xff; i++) { |
for (int i = 0x01, count = 0; i < 0xff; i++) { |
456 |
Glib::ustring sType = |
Glib::ustring sType = |
457 |
dimTypeAsString(static_cast<gig::dimension_t>(i)); |
dimTypeAsString(static_cast<gig::dimension_t>(i)); |
458 |
|
if (i == oldType) oldTypeIndex = count; |
459 |
if (sType.find("Unknown") != 0) { |
if (sType.find("Unknown") != 0) { |
460 |
Gtk::TreeModel::Row row = *(refComboModel->append()); |
Gtk::TreeModel::Row row = *(refComboModel->append()); |
461 |
row[comboModel.m_type_id] = i; |
row[comboModel.m_type_id] = i; |
462 |
row[comboModel.m_type_name] = sType; |
row[comboModel.m_type_name] = sType; |
463 |
|
count++; |
464 |
} |
} |
465 |
} |
} |
466 |
Gtk::Table table(2, 2); |
#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); |
Gtk::Label labelDimType(_("Dimension:"), Gtk::ALIGN_START); |
472 |
Gtk::ComboBox comboDimType; |
Gtk::ComboBox comboDimType; |
473 |
comboDimType.set_model(refComboModel); |
comboDimType.set_model(refComboModel); |
474 |
comboDimType.pack_start(comboModel.m_type_id); |
comboDimType.pack_start(comboModel.m_type_id); |
475 |
comboDimType.pack_start(comboModel.m_type_name); |
comboDimType.pack_start(comboModel.m_type_name); |
|
Gtk::Label labelZones(_("Zones:"), Gtk::ALIGN_START); |
|
476 |
table.attach(labelDimType, 0, 1, 0, 1); |
table.attach(labelDimType, 0, 1, 0, 1); |
477 |
table.attach(comboDimType, 1, 2, 0, 1); |
table.attach(comboDimType, 1, 2, 0, 1); |
478 |
table.attach(labelZones, 0, 1, 1, 2); |
#if USE_GTKMM_BOX |
479 |
dialog.get_vbox()->pack_start(table); |
dialog.get_content_area()->pack_start(table); |
|
|
|
|
// number of zones: use a combo box with fix values for gig |
|
|
// v2 and a spin button for v3 |
|
|
Gtk::ComboBoxText comboZones; |
|
|
Gtk::SpinButton spinZones; |
|
|
bool version2 = false; |
|
|
if (region) { |
|
|
gig::File* file = (gig::File*)region->GetParent()->GetParent(); |
|
|
version2 = file->pVersion && file->pVersion->major == 2; |
|
|
} |
|
|
if (version2) { |
|
|
for (int i = 1; i <= 5; i++) { |
|
|
char buf[3]; |
|
|
sprintf(buf, "%d", 1 << i); |
|
|
#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2 |
|
|
comboZones.append_text(buf); |
|
480 |
#else |
#else |
481 |
comboZones.append(buf); |
dialog.get_vbox()->pack_start(table); |
482 |
#endif |
#endif |
|
} |
|
|
table.attach(comboZones, 1, 2, 1, 2); |
|
|
} else { |
|
|
spinZones.set_increments(1, 8); |
|
|
spinZones.set_numeric(true); |
|
|
spinZones.set_range(2, 128); |
|
|
spinZones.set_value(2); |
|
|
table.attach(spinZones, 1, 2, 1, 2); |
|
|
} |
|
483 |
|
|
484 |
|
#if HAS_GTKMM_STOCK |
485 |
dialog.add_button(Gtk::Stock::OK, 0); |
dialog.add_button(Gtk::Stock::OK, 0); |
486 |
dialog.add_button(Gtk::Stock::CANCEL, 1); |
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(); |
dialog.show_all_children(); |
493 |
|
#endif |
494 |
|
|
495 |
|
comboDimType.set_active(oldTypeIndex); |
496 |
|
|
497 |
if (!dialog.run()) { // OK selected ... |
if (!dialog.run()) { // OK selected ... |
498 |
|
ignoreColumnClicked = true; |
499 |
Gtk::TreeModel::iterator iterType = comboDimType.get_active(); |
Gtk::TreeModel::iterator iterType = comboDimType.get_active(); |
500 |
if (!iterType) return; |
if (!iterType) return; |
501 |
Gtk::TreeModel::Row rowType = *iterType; |
Gtk::TreeModel::Row rowType = *iterType; |
502 |
if (!rowType) return; |
if (!rowType) return; |
|
gig::dimension_def_t dim; |
|
503 |
int iTypeID = rowType[comboModel.m_type_id]; |
int iTypeID = rowType[comboModel.m_type_id]; |
504 |
dim.dimension = static_cast<gig::dimension_t>(iTypeID); |
gig::dimension_t newType = static_cast<gig::dimension_t>(iTypeID); |
505 |
|
if (newType == oldType) return; |
506 |
if (version2) { |
//printf("change 0x%x -> 0x%x\n", oldType, newType); |
507 |
if (comboZones.get_active_row_number() < 0) return; |
|
508 |
dim.bits = comboZones.get_active_row_number() + 1; |
// assemble the list of regions where the selected dimension type |
509 |
dim.zones = 1 << dim.bits; |
// shall be changed |
510 |
} else { |
std::vector<gig::Region*> vRegions; |
511 |
dim.zones = spinZones.get_value_as_int(); |
if (allRegions()) { |
512 |
// Find the number of bits required to hold the |
gig::Instrument* instr = (gig::Instrument*)region->GetParent(); |
513 |
// specified amount of zones. |
for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) { |
514 |
int zoneBits = dim.zones - 1; |
if (rgn->GetDimensionDefinition(oldType)) vRegions.push_back(rgn); |
515 |
for (dim.bits = 0; zoneBits > 1; dim.bits += 2, zoneBits >>= 2); |
} |
516 |
dim.bits += zoneBits; |
} else vRegions.push_back(region); |
517 |
} |
|
518 |
printf( |
std::set<Glib::ustring> errors; |
519 |
"Adding dimension (type=0x%x, bits=%d, zones=%d)\n", |
|
520 |
dim.dimension, dim.bits, dim.zones |
for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) { |
521 |
); |
gig::Region* region = vRegions[iRgn]; |
522 |
// notify everybody that we're going to update the region |
try { |
523 |
region_to_be_changed_signal.emit(region); |
// notify everybody that we're going to update the region |
524 |
// add the new dimension to the region |
region_to_be_changed_signal.emit(region); |
525 |
// (implicitly creates new dimension regions) |
// change the dimension type on that region |
526 |
region->AddDimension(&dim); |
region->SetDimensionType(oldType, newType); |
527 |
// let everybody know there was a change |
// let everybody know there was a change |
528 |
region_changed_signal.emit(region); |
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 |
// update all GUI elements |
544 |
refreshManager(); |
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 |
} catch (RIFF::Exception e) { |
} else if (focus_column == treeView.get_column(1) || focus_column == treeView.get_column(2)) { |
566 |
// notify that the changes are over (i.e. to avoid dead locks) |
Glib::ustring txt = _("Right-click on a specific dimension zone of the dimension region selector to delete or split that particular dimension zone!"); |
567 |
region_changed_signal.emit(region); |
Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_INFO); |
|
// show error message |
|
|
Glib::ustring txt = _("Could not add dimension: ") + e.Message; |
|
|
Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR); |
|
568 |
msg.run(); |
msg.run(); |
569 |
} |
} |
570 |
} |
} |
571 |
|
|
572 |
void DimensionManager::removeDimension() { |
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(); |
Glib::RefPtr<Gtk::TreeSelection> sel = treeView.get_selection(); |
736 |
Gtk::TreeModel::iterator it = sel->get_selected(); |
Gtk::TreeModel::iterator it = sel->get_selected(); |
737 |
if (it) { |
if (it) { |
738 |
try { |
Gtk::TreeModel::Row row = *it; |
739 |
// notify everybody that we're going to update the region |
gig::dimension_t type = row[tableModel.m_type]; |
740 |
region_to_be_changed_signal.emit(region); |
|
741 |
// remove selected dimension |
// assemble the list of regions where the selected dimension shall be |
742 |
Gtk::TreeModel::Row row = *it; |
// added to |
743 |
gig::dimension_def_t* dim = row[tableModel.m_definition]; |
std::vector<gig::Region*> vRegions; |
744 |
region->DeleteDimension(dim); |
if (allRegions()) { |
745 |
// let everybody know there was a change |
gig::Instrument* instr = (gig::Instrument*)region->GetParent(); |
746 |
region_changed_signal.emit(region); |
for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) { |
747 |
// update all GUI elements |
if (rgn->GetDimensionDefinition(type)) vRegions.push_back(rgn); |
748 |
refreshManager(); |
} |
749 |
} catch (RIFF::Exception e) { |
} else vRegions.push_back(region); |
750 |
// notify that the changes are over (i.e. to avoid dead locks) |
|
751 |
region_changed_signal.emit(region); |
std::set<Glib::ustring> errors; |
752 |
// show error message |
|
753 |
Glib::ustring txt = _("Could not remove dimension: ") + e.Message; |
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); |
Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR); |
796 |
msg.run(); |
msg.run(); |
797 |
} |
} |