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

Legend:
Removed from v.1411  
changed lines
  Added in v.3158

  ViewVC Help
Powered by ViewVC