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

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

  ViewVC Help
Powered by ViewVC