/[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 1225 by schoenebeck, Sun Jun 10 10:56:11 2007 UTC revision 3225 by schoenebeck, Fri May 26 22:10:16 2017 UTC
# Line 1  Line 1 
1  /*                                                         -*- c++ -*-  /*
2   * Copyright (C) 2006, 2007 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 <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        if (!Settings::singleton()->autoRestoreWindowDimension) {
253            set_default_size(630, 250);
254            set_position(Gtk::WIN_POS_MOUSE);
255        }
256    
257        set_title(_("Dimensions of selected Region"));
258      add(vbox);      add(vbox);
259      scrolledWindow.add(treeView);      scrolledWindow.add(treeView);
260      vbox.pack_start(scrolledWindow);      vbox.pack_start(scrolledWindow);
261      scrolledWindow.show();      scrolledWindow.show();
262      vbox.pack_start(buttonBox);      vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
263      buttonBox.set_layout(Gtk::BUTTONBOX_END);      buttonBox.set_layout(Gtk::BUTTONBOX_END);
264      buttonBox.set_border_width(5);      buttonBox.set_border_width(5);
265      buttonBox.show();      buttonBox.show();
266      buttonBox.pack_start(addButton);      buttonBox.pack_start(allRegionsCheckBox, Gtk::PACK_EXPAND_PADDING);
267      buttonBox.pack_start(removeButton);      buttonBox.pack_start(addButton, Gtk::PACK_SHRINK);
268        buttonBox.pack_start(removeButton, Gtk::PACK_SHRINK);
269      addButton.show();      addButton.show();
270      removeButton.show();      removeButton.show();
271        allRegionsCheckBox.set_tooltip_text(
272            _("Enable this if you want to edit dimensions of all regions simultaniously.")
273        );
274    
275      // setup the table      // setup the table
276      refTableModel = Gtk::ListStore::create(tableModel);      refTableModel = Gtk::ListStore::create(tableModel);
277      treeView.set_model(refTableModel);      treeView.set_model(refTableModel);
278      treeView.append_column("Dimension Type", tableModel.m_dim_type);      treeView.append_column(_("Dimension Type"), m_cellRendererDimType);
279      treeView.append_column_numeric("Bits", tableModel.m_bits, "%d");      treeView.append_column(_("Bits"), m_cellRendererIntSet);
280      treeView.append_column_numeric("Zones", tableModel.m_zones, "%d");      treeView.append_column(_("Zones"), m_cellRendererIntSet);
281      treeView.append_column("Description", tableModel.m_description);      treeView.append_column(_("Description"), tableModel.m_description);
282        treeView.get_column(0)->add_attribute(m_cellRendererDimType.propertyDimType(), tableModel.m_type);
283        treeView.get_column(0)->add_attribute(m_cellRendererDimType.propertyUsageCount(), tableModel.m_usageCount);
284        treeView.get_column(0)->add_attribute(m_cellRendererDimType.propertyTotalRegions(), tableModel.m_totalRegions);
285        treeView.get_column(1)->add_attribute(m_cellRendererIntSet.propertyValue(), tableModel.m_bits);
286        treeView.get_column(2)->add_attribute(m_cellRendererIntSet.propertyValue(), tableModel.m_zones);
287      treeView.show();      treeView.show();
288    
289        treeView.signal_cursor_changed().connect(
290            sigc::mem_fun(*this, &DimensionManager::onColumnClicked)
291        );
292    
293      addButton.signal_clicked().connect(      addButton.signal_clicked().connect(
294          sigc::mem_fun(*this, &DimensionManager::addDimension)          sigc::mem_fun(*this, &DimensionManager::addDimension)
295      );      );
# Line 211  addButton(Gtk::Stock::ADD), removeButton Line 297  addButton(Gtk::Stock::ADD), removeButton
297      removeButton.signal_clicked().connect(      removeButton.signal_clicked().connect(
298          sigc::mem_fun(*this, &DimensionManager::removeDimension)          sigc::mem_fun(*this, &DimensionManager::removeDimension)
299      );      );
300        allRegionsCheckBox.signal_toggled().connect(
301            sigc::mem_fun(*this, &DimensionManager::onAllRegionsCheckBoxToggled)
302        );
303    
304      show_all_children();      show_all_children();
305  }  }
306    
307    bool DimensionManager::allRegions() const {
308        return allRegionsCheckBox.get_active();
309    }
310    
311    void DimensionManager::onAllRegionsCheckBoxToggled() {
312        set_title(
313            allRegions() ? _("Dimensions of all Regions") :  _("Dimensions of selected Region")
314        );
315        treeView.set_tooltip_text(
316            allRegions()
317                ? _("Dimensions and numbers in gray indicates a difference among the individual regions.")
318                : _("You are currently only viewing dimensions of the currently selected region.")
319        );
320        refreshManager();
321    }
322    
323    // following two data types are just used in DimensionManager::refresManager(),
324    // due to the maps template nature however, they must be declared at global
325    // space to avoid compilation errors
326    struct _DimDef {
327        std::set<int> bits;
328        std::set<int> zones;
329        int usageCount;
330    };
331    typedef std::map<gig::dimension_t, _DimDef> _Dimensions;
332    
333  // update all GUI elements according to current gig::Region informations  // update all GUI elements according to current gig::Region informations
334  void DimensionManager::refreshManager() {  void DimensionManager::refreshManager() {
335        set_sensitive(false);
336      refTableModel->clear();      refTableModel->clear();
337      for (int i = 0; i < region->Dimensions; i++) {      if (allRegions()) {
338          gig::dimension_def_t* dim = &region->pDimensionDefinitions[i];          if (region) {
339          Gtk::TreeModel::Row row = *(refTableModel->append());              _Dimensions dims;
340          row[tableModel.m_dim_type] = __dimTypeAsString(dim->dimension);              gig::Instrument* instr = (gig::Instrument*)region->GetParent();
341          row[tableModel.m_bits] = dim->bits;              int iRegionsCount = 0;
342          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) {
343          row[tableModel.m_description] = __dimDescriptionAsString(dim->dimension);                  for (uint i = 0; i < rgn->Dimensions; i++) {
344          row[tableModel.m_definition] = dim;                      gig::dimension_def_t* dim = &rgn->pDimensionDefinitions[i];
345                        dims[dim->dimension].bits.insert(dim->bits);
346                        dims[dim->dimension].zones.insert(dim->zones);
347                        dims[dim->dimension].usageCount++;
348                    }
349                }
350                for (_Dimensions::const_iterator it = dims.begin(); it != dims.end(); ++it) {
351                    Gtk::TreeModel::Row row = *(refTableModel->append());
352                    row[tableModel.m_type] = it->first;
353                    row[tableModel.m_bits] = it->second.bits;
354                    row[tableModel.m_zones] = it->second.zones;
355                    row[tableModel.m_description] = __dimDescriptionAsString(it->first);
356                    row[tableModel.m_usageCount] = it->second.usageCount;
357                    row[tableModel.m_totalRegions] = iRegionsCount;
358                }
359            }
360        } else {
361            if (region) {
362                for (uint i = 0; i < region->Dimensions; i++) {
363                    gig::dimension_def_t* dim = &region->pDimensionDefinitions[i];
364                    Gtk::TreeModel::Row row = *(refTableModel->append());
365                    std::set<int> vBits;
366                    vBits.insert(dim->bits);
367                    row[tableModel.m_bits] = vBits;
368                    std::set<int> vZones;
369                    vZones.insert(dim->zones);
370                    row[tableModel.m_zones] = vZones;
371                    row[tableModel.m_description] = __dimDescriptionAsString(dim->dimension);
372                    row[tableModel.m_type] = dim->dimension;
373                    row[tableModel.m_usageCount] = 1;
374                    row[tableModel.m_totalRegions] = 1;
375                }
376            }
377      }      }
378        set_sensitive(region);
379  }  }
380    
381  void DimensionManager::show(gig::Region* region) {  void DimensionManager::show(gig::Region* region) {
382        ignoreColumnClicked = true;
383      this->region = region;      this->region = region;
384      refreshManager();      refreshManager();
385      Gtk::Window::show();      Gtk::Window::show();
386      deiconify();      deiconify();
387        ignoreColumnClicked = false;
388  }  }
389    
390  void DimensionManager::addDimension() {  void DimensionManager::set_region(gig::Region* region) {
391      try {      ignoreColumnClicked = true;
392          Gtk::Dialog dialog("New Dimension", true /*modal*/);      this->region = region;
393          // add dimension type combo box to the dialog      refreshManager();
394        ignoreColumnClicked = false;
395    }
396    
397    void DimensionManager::onColumnClicked() {
398        printf("DimensionManager::onColumnClicked()\n");
399    
400        //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 !
401    
402        //HACK: Prevents that onColumnClicked() gets called multiple times or at times where it is not desired
403        if (ignoreColumnClicked) {
404            ignoreColumnClicked = false;
405            return;
406        }
407    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 18) || GTKMM_MAJOR_VERSION > 2
408        // prevents app to crash if this dialog is closed
409        if (!get_visible())
410            return;
411    #else
412    # warning Your GTKMM version is too old; dimension manager dialog might crash when changing a dimension type !
413    #endif
414    
415    #if (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION >= 8) || GTKMM_MAJOR_VERSION > 3
416        if (!is_visible()) return;
417    #endif
418    
419        Gtk::TreeModel::Path path;
420        Gtk::TreeViewColumn* focus_column;
421        treeView.get_cursor(path, focus_column);
422        //const int row = path[0];
423        if (focus_column == treeView.get_column(0)) {
424            Gtk::TreeModel::iterator it = treeView.get_model()->get_iter(path);
425            if (!it) return;
426            Gtk::TreeModel::Row row = *it;
427            gig::dimension_t oldType = row[tableModel.m_type];
428    
429            Gtk::Dialog dialog(_("Change Dimension"), true /*modal*/);
430            int oldTypeIndex = -1;
431          Glib::RefPtr<Gtk::ListStore> refComboModel = Gtk::ListStore::create(comboModel);          Glib::RefPtr<Gtk::ListStore> refComboModel = Gtk::ListStore::create(comboModel);
432          for (int i = 0x01; i < 0xff; i++) {          for (int i = 0x01, count = 0; i < 0xff; i++) {
433              Glib::ustring sType =              Glib::ustring sType =
434                  __dimTypeAsString(static_cast<gig::dimension_t>(i));                  dimTypeAsString(static_cast<gig::dimension_t>(i));
435                if (i == oldType) oldTypeIndex = count;
436              if (sType.find("Unknown") != 0) {              if (sType.find("Unknown") != 0) {
437                  Gtk::TreeModel::Row row = *(refComboModel->append());                  Gtk::TreeModel::Row row = *(refComboModel->append());
438                  row[comboModel.m_type_id]   = i;                  row[comboModel.m_type_id]   = i;
439                  row[comboModel.m_type_name] = sType;                  row[comboModel.m_type_name] = sType;
440                    count++;
441              }              }
442          }          }
443            Gtk::Table table(1, 2);
444            Gtk::Label labelDimType(_("Dimension:"), Gtk::ALIGN_START);
445          Gtk::ComboBox comboDimType;          Gtk::ComboBox comboDimType;
446          comboDimType.set_model(refComboModel);          comboDimType.set_model(refComboModel);
447          comboDimType.pack_start(comboModel.m_type_id);          comboDimType.pack_start(comboModel.m_type_id);
448          comboDimType.pack_start(comboModel.m_type_name);          comboDimType.pack_start(comboModel.m_type_name);
449          dialog.get_vbox()->pack_start(comboDimType);          table.attach(labelDimType, 0, 1, 0, 1);
450          comboDimType.show();          table.attach(comboDimType, 1, 2, 0, 1);
451          // add zones combo box to the dialog          dialog.get_vbox()->pack_start(table);
452          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  
453          dialog.add_button(Gtk::Stock::OK, 0);          dialog.add_button(Gtk::Stock::OK, 0);
454          dialog.add_button(Gtk::Stock::CANCEL, 1);          dialog.add_button(Gtk::Stock::CANCEL, 1);
455          dialog.show_all_children();          dialog.show_all_children();
456            
457            comboDimType.set_active(oldTypeIndex);
458    
459          if (!dialog.run()) { // OK selected ...          if (!dialog.run()) { // OK selected ...
460                ignoreColumnClicked = true;
461              Gtk::TreeModel::iterator iterType = comboDimType.get_active();              Gtk::TreeModel::iterator iterType = comboDimType.get_active();
462              if (!iterType) return;              if (!iterType) return;
463              Gtk::TreeModel::Row rowType = *iterType;              Gtk::TreeModel::Row rowType = *iterType;
464              if (!rowType) return;              if (!rowType) return;
             gig::dimension_def_t dim;  
465              int iTypeID = rowType[comboModel.m_type_id];              int iTypeID = rowType[comboModel.m_type_id];
466              dim.dimension = static_cast<gig::dimension_t>(iTypeID);              gig::dimension_t newType = static_cast<gig::dimension_t>(iTypeID);
467              if (comboZones.get_active_row_number() < 0) return;              if (newType == oldType) return;
468              dim.bits = comboZones.get_active_row_number() + 1;              //printf("change 0x%x -> 0x%x\n", oldType, newType);
469              dim.zones = 1 << dim.bits; //TODO: support zones != pow(2,bits) - feature of gig v3  
470              printf(              // assemble the list of regions where the selected dimension type
471                  "Adding dimension (type=0x%x, bits=%d, zones=%d)\n",              // shall be changed
472                  dim.dimension, dim.bits, dim.zones              std::vector<gig::Region*> vRegions;
473              );              if (allRegions()) {
474              // add the new dimension to the region                  gig::Instrument* instr = (gig::Instrument*)region->GetParent();
475              // (implicitly creates new dimension regions)                  for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
476              region->AddDimension(&dim);                      if (rgn->GetDimensionDefinition(oldType)) vRegions.push_back(rgn);
477              // let everybody know there was a change                  }
478              articulation_changed_signal.emit();              } else vRegions.push_back(region);
479    
480                std::set<Glib::ustring> errors;
481    
482                for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
483                    gig::Region* region = vRegions[iRgn];
484                    try {
485                        // notify everybody that we're going to update the region
486                        region_to_be_changed_signal.emit(region);
487                        // change the dimension type on that region
488                        region->SetDimensionType(oldType, newType);
489                        // let everybody know there was a change
490                        region_changed_signal.emit(region);
491                    } catch (RIFF::Exception e) {
492                        // notify that the changes are over (i.e. to avoid dead locks)
493                        region_changed_signal.emit(region);
494                        Glib::ustring txt = _("Could not alter dimension: ") + e.Message;
495                        if (vRegions.size() == 1) {
496                            // show error message directly
497                            Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
498                            msg.run();
499                        } else {
500                            // remember error, they are shown after all regions have been processed
501                            errors.insert(txt);
502                        }
503                    }
504                }
505              // update all GUI elements              // update all GUI elements
506              refreshManager();              refreshManager();
507    
508                if (!errors.empty()) {
509                    Glib::ustring txt = _(
510                        "The following errors occurred while trying to change the dimension type on all regions:"
511                    );
512                    txt += "\n\n";
513                    for (std::set<Glib::ustring>::const_iterator it = errors.begin();
514                        it != errors.end(); ++it)
515                    {
516                        txt += "-> " + *it + "\n";
517                    }
518                    txt += "\n";
519                    txt += _(
520                        "You might also want to check the console for further warnings and "
521                        "error messages."
522                    );
523                    Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
524                    msg.run();
525                }
526          }          }
527      } catch (RIFF::Exception e) {      } else if (focus_column == treeView.get_column(1) || focus_column == treeView.get_column(2)) {
528          Glib::ustring txt = "Could not add dimension: " + e.Message;          Glib::ustring txt = _("Right-click on a specific dimension zone of the dimension region selector to delete or split that particular dimension zone!");
529          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_INFO);
530          msg.run();          msg.run();
531      }      }
532  }  }
533    
534  void DimensionManager::removeDimension() {  void DimensionManager::addDimension() {
535        Gtk::Dialog dialog(_("New Dimension"), true /*modal*/);
536        // add dimension type combo box to the dialog
537        Glib::RefPtr<Gtk::ListStore> refComboModel = Gtk::ListStore::create(comboModel);
538        for (int i = 0x01; i < 0xff; i++) {
539            Glib::ustring sType =
540                dimTypeAsString(static_cast<gig::dimension_t>(i));
541            if (sType.find("Unknown") != 0) {
542                Gtk::TreeModel::Row row = *(refComboModel->append());
543                row[comboModel.m_type_id]   = i;
544                row[comboModel.m_type_name] = sType;
545            }
546        }
547        Gtk::Table table(2, 2);
548        Gtk::Label labelDimType(_("Dimension:"), Gtk::ALIGN_START);
549        Gtk::ComboBox comboDimType;
550        comboDimType.set_model(refComboModel);
551        comboDimType.pack_start(comboModel.m_type_id);
552        comboDimType.pack_start(comboModel.m_type_name);
553        Gtk::Label labelZones(_("Zones:"), Gtk::ALIGN_START);
554        table.attach(labelDimType, 0, 1, 0, 1);
555        table.attach(comboDimType, 1, 2, 0, 1);
556        table.attach(labelZones, 0, 1, 1, 2);
557        dialog.get_vbox()->pack_start(table);
558    
559        // number of zones: use a combo box with fix values for gig
560        // v2 and a spin button for v3
561        Gtk::ComboBoxText comboZones;
562        Gtk::SpinButton spinZones;
563        bool version2 = false;
564        if (region) {
565            gig::File* file = (gig::File*)region->GetParent()->GetParent();
566            version2 = file->pVersion && file->pVersion->major == 2;
567        }
568        if (version2) {
569            for (int i = 1; i <= 5; i++) {
570                char buf[3];
571                sprintf(buf, "%d", 1 << i);
572    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
573                comboZones.append_text(buf);
574    #else
575                comboZones.append(buf);
576    #endif
577            }
578            table.attach(comboZones, 1, 2, 1, 2);
579        } else {
580            spinZones.set_increments(1, 8);
581            spinZones.set_numeric(true);
582            spinZones.set_range(2, 128);
583            spinZones.set_value(2);
584            table.attach(spinZones, 1, 2, 1, 2);
585        }
586    
587        dialog.add_button(Gtk::Stock::OK, 0);
588        dialog.add_button(Gtk::Stock::CANCEL, 1);
589        dialog.show_all_children();
590    
591        if (!dialog.run()) { // OK selected ...
592            Gtk::TreeModel::iterator iterType = comboDimType.get_active();
593            if (!iterType) return;
594            Gtk::TreeModel::Row rowType = *iterType;
595            if (!rowType) return;
596            int iTypeID = rowType[comboModel.m_type_id];
597            gig::dimension_t type = static_cast<gig::dimension_t>(iTypeID);
598            gig::dimension_def_t dim;
599            dim.dimension = type;
600    
601            if (version2) {
602                if (comboZones.get_active_row_number() < 0) return;
603                dim.bits = comboZones.get_active_row_number() + 1;
604                dim.zones = 1 << dim.bits;
605            } else {
606                dim.zones = spinZones.get_value_as_int();
607                dim.bits = zoneCountToBits(dim.zones);
608            }
609    
610            // assemble the list of regions where the selected dimension shall be
611            // added to
612            std::vector<gig::Region*> vRegions;
613            if (allRegions()) {
614                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
615                for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
616                    if (!rgn->GetDimensionDefinition(type)) vRegions.push_back(rgn);
617                }
618            } else vRegions.push_back(region);
619                
620            std::set<Glib::ustring> errors;
621    
622            for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
623                gig::Region* region = vRegions[iRgn];
624                try {
625                    printf(
626                        "Adding dimension (type=0x%x, bits=%d, zones=%d)\n",
627                        dim.dimension, dim.bits, dim.zones
628                    );
629                    // notify everybody that we're going to update the region
630                    region_to_be_changed_signal.emit(region);
631                    // add the new dimension to the region
632                    // (implicitly creates new dimension regions)
633                    region->AddDimension(&dim);
634                    // let everybody know there was a change
635                    region_changed_signal.emit(region);
636                } catch (RIFF::Exception e) {
637                    // notify that the changes are over (i.e. to avoid dead locks)
638                    region_changed_signal.emit(region);
639                    Glib::ustring txt = _("Could not add dimension: ") + e.Message;
640                    if (vRegions.size() == 1) {
641                        // show error message directly
642                        Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
643                        msg.run();
644                    } else {
645                        // remember error, they are shown after all regions have been processed
646                        errors.insert(txt);
647                    }
648                }
649            }
650            // update all GUI elements
651            refreshManager();
652    
653            if (!errors.empty()) {
654                Glib::ustring txt = _(
655                    "The following errors occurred while trying to create the dimension on all regions:"
656                );
657                txt += "\n\n";
658                for (std::set<Glib::ustring>::const_iterator it = errors.begin();
659                     it != errors.end(); ++it)
660                {
661                    txt += "-> " + *it + "\n";
662                }
663                txt += "\n";
664                txt += _(
665                    "You might also want to check the console for further warnings and "
666                    "error messages."
667                );
668                Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
669                msg.run();
670            }
671        }
672    }
673    
674    void DimensionManager::removeDimension() {        
675      Glib::RefPtr<Gtk::TreeSelection> sel = treeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = treeView.get_selection();
676      Gtk::TreeModel::iterator it = sel->get_selected();      Gtk::TreeModel::iterator it = sel->get_selected();
677      if (it) {      if (it) {
678          try {          Gtk::TreeModel::Row row = *it;
679              // remove selected dimension          gig::dimension_t type = row[tableModel.m_type];
680              Gtk::TreeModel::Row row = *it;  
681              gig::dimension_def_t* dim = row[tableModel.m_definition];          // assemble the list of regions where the selected dimension shall be
682              region->DeleteDimension(dim);          // added to
683              // remove respective row from table          std::vector<gig::Region*> vRegions;
684              refTableModel->erase(it);          if (allRegions()) {
685              // let everybody know there was a change              gig::Instrument* instr = (gig::Instrument*)region->GetParent();
686              articulation_changed_signal.emit();              for (gig::Region* rgn = instr->GetFirstRegion(); rgn; rgn = instr->GetNextRegion()) {
687          } catch (RIFF::Exception e) {                  if (rgn->GetDimensionDefinition(type)) vRegions.push_back(rgn);
688              Glib::ustring txt = "Could not remove dimension: " + e.Message;              }
689            } else vRegions.push_back(region);
690    
691            std::set<Glib::ustring> errors;
692    
693            for (uint iRgn = 0; iRgn < vRegions.size(); ++iRgn) {
694                gig::Region* region = vRegions[iRgn];
695                gig::dimension_def_t* dim = region->GetDimensionDefinition(type);
696                try {
697                    // notify everybody that we're going to update the region
698                    region_to_be_changed_signal.emit(region);
699                    // remove selected dimension    
700                    region->DeleteDimension(dim);
701                    // let everybody know there was a change
702                    region_changed_signal.emit(region);
703                } catch (RIFF::Exception e) {
704                    // notify that the changes are over (i.e. to avoid dead locks)
705                    region_changed_signal.emit(region);
706                    Glib::ustring txt = _("Could not remove dimension: ") + e.Message;
707                    if (vRegions.size() == 1) {
708                        // show error message directly
709                        Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
710                        msg.run();
711                    } else {
712                        // remember error, they are shown after all regions have been processed
713                        errors.insert(txt);
714                    }
715                }
716            }
717            // update all GUI elements
718            refreshManager();
719    
720            if (!errors.empty()) {
721                Glib::ustring txt = _(
722                    "The following errors occurred while trying to remove the dimension from all regions:"
723                );
724                txt += "\n\n";
725                for (std::set<Glib::ustring>::const_iterator it = errors.begin();
726                     it != errors.end(); ++it)
727                {
728                    txt += "-> " + *it + "\n";
729                }
730                txt += "\n";
731                txt += _(
732                    "You might also want to check the console for further warnings and "
733                    "error messages."
734                );
735              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
736              msg.run();              msg.run();
737          }          }

Legend:
Removed from v.1225  
changed lines
  Added in v.3225

  ViewVC Help
Powered by ViewVC