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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2507 by persson, Sun Jan 12 19:37:55 2014 UTC revision 3364 by schoenebeck, Tue Nov 14 18:07:25 2017 UTC
# Line 1  Line 1 
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
# Line 17  Line 17 
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"
46    
47  // returns a human readable name of the given dimension type  // returns a human readable name of the given dimension type
48  static Glib::ustring __dimTypeAsString(gig::dimension_t d) {  Glib::ustring dimTypeAsString(gig::dimension_t d) {
49      char buf[32];      char buf[32];
50      switch (d) {      switch (d) {
51          case gig::dimension_none:          case gig::dimension_none:
# Line 183  static Glib::ustring __dimDescriptionAsS Line 198  static Glib::ustring __dimDescriptionAsS
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);
# Line 193  addButton(Gtk::Stock::ADD), removeButton Line 278  addButton(Gtk::Stock::ADD), removeButton
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      );      );
# Line 216  addButton(Gtk::Stock::ADD), removeButton Line 318  addButton(Gtk::Stock::ADD), removeButton
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    }
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 = &region->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 = &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);      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          }          }

Legend:
Removed from v.2507  
changed lines
  Added in v.3364

  ViewVC Help
Powered by ViewVC