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

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

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

revision 2579 by persson, Sat May 24 06:44:39 2014 UTC revision 3782 by schoenebeck, Fri May 29 23:25:06 2020 UTC
# Line 1  Line 1 
1  /*  /*
2      Copyright (c) 2014 Christian Schoenebeck      Copyright (c) 2014-2020 Christian Schoenebeck
3        
4      This file is part of "gigedit" and released under the terms of the      This file is part of "gigedit" and released under the terms of the
5      GNU General Public License version 2.      GNU General Public License version 2.
6  */  */
7    
8    #include "global.h"
9  #include "CombineInstrumentsDialog.h"  #include "CombineInstrumentsDialog.h"
10    
11  // enable this for debug messages being printed while combining the instruments  // enable this for debug messages being printed while combining the instruments
12  #define DEBUG_COMBINE_INSTRUMENTS 0  #define DEBUG_COMBINE_INSTRUMENTS 0
13    
 #include "global.h"  
14  #include "compat.h"  #include "compat.h"
15    
16  #include <set>  #include <set>
# Line 20  Line 20 
20  #include <string.h>  #include <string.h>
21    
22  #include <glibmm/ustring.h>  #include <glibmm/ustring.h>
23  #include <gtkmm/stock.h>  #if HAS_GTKMM_STOCK
24    # include <gtkmm/stock.h>
25    #endif
26  #include <gtkmm/messagedialog.h>  #include <gtkmm/messagedialog.h>
27  #include <gtkmm/label.h>  #include <gtkmm/label.h>
28    #include <gtk/gtkwidget.h> // for gtk_widget_modify_*()
29    
 Glib::ustring gig_to_utf8(const gig::String& gig_string);  
30  Glib::ustring dimTypeAsString(gig::dimension_t d);  Glib::ustring dimTypeAsString(gig::dimension_t d);
31    
32  typedef std::vector< std::pair<gig::Instrument*, gig::Region*> > OrderedRegionGroup;  typedef std::vector< std::pair<gig::Instrument*, gig::Region*> > OrderedRegionGroup;
# Line 34  typedef std::map<DLS::range_t,RegionGrou Line 36  typedef std::map<DLS::range_t,RegionGrou
36  typedef std::vector<DLS::range_t> DimensionZones;  typedef std::vector<DLS::range_t> DimensionZones;
37  typedef std::map<gig::dimension_t,DimensionZones> Dimensions;  typedef std::map<gig::dimension_t,DimensionZones> Dimensions;
38    
 typedef std::map<gig::dimension_t,int> DimensionCase;  
   
39  typedef std::map<gig::dimension_t, int> DimensionRegionUpperLimits;  typedef std::map<gig::dimension_t, int> DimensionRegionUpperLimits;
40    
41  typedef std::set<Glib::ustring> Warnings;  typedef std::set<Glib::ustring> Warnings;
# Line 97  inline int smallestOverlapPoint(const DL Line 97  inline int smallestOverlapPoint(const DL
97   *          found with a range member point >= iStart   *          found with a range member point >= iStart
98   */   */
99  static int findLowestRegionPoint(std::vector<gig::Instrument*>& instruments, int iStart) {  static int findLowestRegionPoint(std::vector<gig::Instrument*>& instruments, int iStart) {
100      DLS::range_t searchRange = { iStart, 127 };      DLS::range_t searchRange = { uint16_t(iStart), 127 };
101      int result = -1;      int result = -1;
102      for (uint i = 0; i < instruments.size(); ++i) {      for (uint i = 0; i < instruments.size(); ++i) {
103          gig::Instrument* instr = instruments[i];          gig::Instrument* instr = instruments[i];
# Line 119  static int findLowestRegionPoint(std::ve Line 119  static int findLowestRegionPoint(std::ve
119   *          with a range end >= iStart   *          with a range end >= iStart
120   */   */
121  static int findFirstRegionEnd(std::vector<gig::Instrument*>& instruments, int iStart) {  static int findFirstRegionEnd(std::vector<gig::Instrument*>& instruments, int iStart) {
122      DLS::range_t searchRange = { iStart, 127 };      DLS::range_t searchRange = { uint16_t(iStart), 127 };
123      int result = -1;      int result = -1;
124      for (uint i = 0; i < instruments.size(); ++i) {      for (uint i = 0; i < instruments.size(); ++i) {
125          gig::Instrument* instr = instruments[i];          gig::Instrument* instr = instruments[i];
# Line 195  static RegionGroups groupByRegionInterse Line 195  static RegionGroups groupByRegionInterse
195          iStart = findLowestRegionPoint(instruments, iStart);          iStart = findLowestRegionPoint(instruments, iStart);
196          if (iStart < 0) break;          if (iStart < 0) break;
197          const int iEnd = findFirstRegionEnd(instruments, iStart);          const int iEnd = findFirstRegionEnd(instruments, iStart);
198          DLS::range_t range = { iStart, iEnd };          DLS::range_t range = { uint16_t(iStart), uint16_t(iEnd) };
199          intersections.push_back(range);          intersections.push_back(range);
200          iStart = iEnd + 1;          iStart = iEnd + 1;
201      }      }
# Line 217  static RegionGroups groupByRegionInterse Line 217  static RegionGroups groupByRegionInterse
217   *   *
218   * Takes a planned new region (@a regionGroup) as argument and identifies which   * Takes a planned new region (@a regionGroup) as argument and identifies which
219   * precise dimensions would have to be created for that new region, along with   * precise dimensions would have to be created for that new region, along with
220   * the amount of dimension zones and their precise individual zone sizes.   * the amount of dimension zones.
221   *   *
222   * @param regionGroup - planned new region for a new instrument   * @param regionGroup - planned new region for a new instrument
223   * @returns set of dimensions that shall be created for the given planned region   * @returns set of dimensions that shall be created for the given planned region
# Line 225  static RegionGroups groupByRegionInterse Line 225  static RegionGroups groupByRegionInterse
225  static Dimensions getDimensionsForRegionGroup(RegionGroup& regionGroup) {  static Dimensions getDimensionsForRegionGroup(RegionGroup& regionGroup) {
226      std::map<gig::dimension_t, std::set<int> > dimUpperLimits;      std::map<gig::dimension_t, std::set<int> > dimUpperLimits;
227    
228        #if DEBUG_COMBINE_INSTRUMENTS
229        printf("dimUpperLimits = {\n");
230        #endif
231      // collect all dimension region zones' upper limits      // collect all dimension region zones' upper limits
232      for (RegionGroup::iterator it = regionGroup.begin();      for (RegionGroup::iterator it = regionGroup.begin();
233           it != regionGroup.end(); ++it)           it != regionGroup.end(); ++it)
# Line 233  static Dimensions getDimensionsForRegion Line 236  static Dimensions getDimensionsForRegion
236          int previousBits = 0;          int previousBits = 0;
237          for (uint d = 0; d < rgn->Dimensions; ++d) {          for (uint d = 0; d < rgn->Dimensions; ++d) {
238              const gig::dimension_def_t& def = rgn->pDimensionDefinitions[d];              const gig::dimension_def_t& def = rgn->pDimensionDefinitions[d];
239                #if DEBUG_COMBINE_INSTRUMENTS
240                printf("\t[rgn=%p,dim=%#x] = {", rgn, def.dimension);
241                #endif
242              for (uint z = 0; z < def.zones; ++z) {              for (uint z = 0; z < def.zones; ++z) {
243                  int dr = z << previousBits;                  int dr = z << previousBits;
244                  gig::DimensionRegion* dimRgn = rgn->pDimensionRegions[dr];                  gig::DimensionRegion* dimRgn = rgn->pDimensionRegions[dr];
245                  // Store the individual dimension zone sizes (or actually their                  // NOTE: Originally this function collected dimensions' upper
246                  // upper limits here) for each dimension.                  // limits. However that caused combined instruments (e.g. with
247                  // HACK: Note that the velocity dimension is specially handled                  // unequal dimension zone counts, not being a power of two) to
248                  // here. Instead of taking over custom velocity split sizes                  // end up having too many dimension zones and those extra zones
249                  // here, only a bogus number (zone index number) is stored for                  // containing no sample. For that reason we simply collect the
250                  // each velocity zone, that way only the maxiumum amount of                  // required amount of output dimension zones here now instead.
251                  // velocity splits of all regions is stored here, and when their                  const int upperLimit =
252                  // individual DimensionRegions are finally copied (later), the  /*
                 // individual velocity split size are copied by that.  
                 dimUpperLimits[def.dimension].insert(  
253                      (def.dimension == gig::dimension_velocity) ?                      (def.dimension == gig::dimension_velocity) ?
254                          z : (def.split_type == gig::split_type_bit) ?                          z : (def.split_type == gig::split_type_bit) ?
255                              ((z+1) * 128/def.zones - 1) : dimRgn->DimensionUpperLimits[dr]                              ((z+1) * 128/def.zones - 1) : dimRgn->DimensionUpperLimits[dr];
256                  );   */
257                        z;
258                    #if DEBUG_COMBINE_INSTRUMENTS
259                    printf(" %d,", upperLimit);
260                    #endif
261                    dimUpperLimits[def.dimension].insert(upperLimit);
262              }              }
263              previousBits += def.bits;              previousBits += def.bits;
264                #if DEBUG_COMBINE_INSTRUMENTS
265                printf(" }\n");
266                #endif
267          }          }
268      }      }
269        #if DEBUG_COMBINE_INSTRUMENTS
270        printf("}\n");
271        #endif
272    
273      // convert upper limit set to range vector      // convert upper limit set to range vector
274      Dimensions dims;      Dimensions dims;
275        #if DEBUG_COMBINE_INSTRUMENTS
276        printf("dims = {\n");
277        #endif
278      for (std::map<gig::dimension_t, std::set<int> >::const_iterator it = dimUpperLimits.begin();      for (std::map<gig::dimension_t, std::set<int> >::const_iterator it = dimUpperLimits.begin();
279           it != dimUpperLimits.end(); ++it)           it != dimUpperLimits.end(); ++it)
280      {      {
281          gig::dimension_t type = it->first;          gig::dimension_t type = it->first;
282            #if DEBUG_COMBINE_INSTRUMENTS
283            printf("\t[dim=%#x] = {", type);
284            #endif
285          int iLow = 0;          int iLow = 0;
286          for (std::set<int>::const_iterator itNums = it->second.begin();          for (std::set<int>::const_iterator itNums = it->second.begin();
287               itNums != it->second.end(); ++itNums)               itNums != it->second.end(); ++itNums)
288          {          {
289              const int iUpperLimit = *itNums;              const int iUpperLimit = *itNums;
290              DLS::range_t range = { iLow, iUpperLimit };              DLS::range_t range = { uint16_t(iLow), uint16_t(iUpperLimit) };
291              dims[type].push_back(range);              dims[type].push_back(range);
292                #if DEBUG_COMBINE_INSTRUMENTS
293                printf(" %d..%d,", iLow, iUpperLimit);
294                #endif
295              iLow = iUpperLimit + 1;              iLow = iUpperLimit + 1;
296          }          }
297            #if DEBUG_COMBINE_INSTRUMENTS
298            printf(" }\n");
299            #endif
300      }      }
301        #if DEBUG_COMBINE_INSTRUMENTS
302        printf("}\n");
303        #endif
304    
305      return dims;      return dims;
306  }  }
307    
 inline int getDimensionIndex(gig::dimension_t type, gig::Region* rgn) {  
     for (uint i = 0; i < rgn->Dimensions; ++i)  
         if (rgn->pDimensionDefinitions[i].dimension == type)  
             return i;  
     return -1;  
 }  
   
308  static void fillDimValues(uint* values/*[8]*/, DimensionCase dimCase, gig::Region* rgn, bool bShouldHaveAllDimensionsPassed) {  static void fillDimValues(uint* values/*[8]*/, DimensionCase dimCase, gig::Region* rgn, bool bShouldHaveAllDimensionsPassed) {
309      #if DEBUG_COMBINE_INSTRUMENTS      #if DEBUG_COMBINE_INSTRUMENTS
310      printf("dimvalues = { ");      printf("dimvalues = { ");
# Line 294  static void fillDimValues(uint* values/* Line 317  static void fillDimValues(uint* values/*
317          else if (iDimIndex < 0) continue;          else if (iDimIndex < 0) continue;
318          values[iDimIndex] = it->second;          values[iDimIndex] = it->second;
319          #if DEBUG_COMBINE_INSTRUMENTS          #if DEBUG_COMBINE_INSTRUMENTS
320          printf("%x=%d, ", type, it->second);          printf("0x%x=%d, ", type, it->second);
321          #endif          #endif
322      }      }
323      #if DEBUG_COMBINE_INSTRUMENTS      #if DEBUG_COMBINE_INSTRUMENTS
# Line 323  static void restoreDimensionRegionUpperL Line 346  static void restoreDimensionRegionUpperL
346      }      }
347  }  }
348    
 /**  
  * Returns the sum of all bits of all dimensions defined before the given  
  * dimensions (@a type). This allows to access cases of that particular  
  * dimension directly.  
  *  
  * @param type - dimension that shall be used  
  * @param rgn - parent region of that dimension  
  */  
 inline int baseBits(gig::dimension_t type, gig::Region* rgn) {  
     int previousBits = 0;  
     for (uint i = 0; i < rgn->Dimensions; ++i) {  
         if (rgn->pDimensionDefinitions[i].dimension == type) break;  
         previousBits += rgn->pDimensionDefinitions[i].bits;  
     }  
     return previousBits;  
 }  
   
349  inline int dimensionRegionIndex(gig::DimensionRegion* dimRgn) {  inline int dimensionRegionIndex(gig::DimensionRegion* dimRgn) {
350      gig::Region* rgn = dimRgn->GetParent();      gig::Region* rgn = dimRgn->GetParent();
351      int sz = sizeof(rgn->pDimensionRegions) / sizeof(gig::DimensionRegion*);      int sz = sizeof(rgn->pDimensionRegions) / sizeof(gig::DimensionRegion*);
# Line 372  static DimensionZones preciseDimensionZo Line 378  static DimensionZones preciseDimensionZo
378      const gig::dimension_def_t& def = rgn->pDimensionDefinitions[iDimension];      const gig::dimension_def_t& def = rgn->pDimensionDefinitions[iDimension];
379      int iDimRgn = dimensionRegionIndex(dimRgn);      int iDimRgn = dimensionRegionIndex(dimRgn);
380      int iBaseBits = baseBits(type, rgn);      int iBaseBits = baseBits(type, rgn);
381        assert(iBaseBits >= 0);
382      int mask = ~(((1 << def.bits) - 1) << iBaseBits);      int mask = ~(((1 << def.bits) - 1) << iBaseBits);
383    
384      #if DEBUG_COMBINE_INSTRUMENTS      #if DEBUG_COMBINE_INSTRUMENTS
# Line 383  static DimensionZones preciseDimensionZo Line 390  static DimensionZones preciseDimensionZo
390          gig::DimensionRegion* dimRgn2 =          gig::DimensionRegion* dimRgn2 =
391              rgn->pDimensionRegions[ (iDimRgn & mask) | ( z << iBaseBits) ];              rgn->pDimensionRegions[ (iDimRgn & mask) | ( z << iBaseBits) ];
392          int iHigh = dimRgn2->DimensionUpperLimits[iDimension];          int iHigh = dimRgn2->DimensionUpperLimits[iDimension];
393          DLS::range_t range = { iLow, iHigh};          DLS::range_t range = { uint16_t(iLow), uint16_t(iHigh) };
394          #if DEBUG_COMBINE_INSTRUMENTS          #if DEBUG_COMBINE_INSTRUMENTS
395          printf("%d..%d, ", iLow, iHigh);          printf("%d..%d, ", iLow, iHigh);
396          fflush(stdout);          fflush(stdout);
# Line 469  static void scheduleCopyDimensionRegions Line 476  static void scheduleCopyDimensionRegions
476          #if DEBUG_COMBINE_INSTRUMENTS          #if DEBUG_COMBINE_INSTRUMENTS
477          printf("dst "); fflush(stdout);          printf("dst "); fflush(stdout);
478          #endif          #endif
479          fillDimValues(dstDimValues, dstDimCase, outRgn, true);          fillDimValues(dstDimValues, dstDimCase, outRgn, false);
480          gig::DimensionRegion* srcDimRgn = inRgn->GetDimensionRegionByValue(srcDimValues);          gig::DimensionRegion* srcDimRgn = inRgn->GetDimensionRegionByValue(srcDimValues);
481          gig::DimensionRegion* dstDimRgn = outRgn->GetDimensionRegionByValue(dstDimValues);          gig::DimensionRegion* dstDimRgn = outRgn->GetDimensionRegionByValue(dstDimValues);
482          #if DEBUG_COMBINE_INSTRUMENTS          #if DEBUG_COMBINE_INSTRUMENTS
# Line 505  static void scheduleCopyDimensionRegions Line 512  static void scheduleCopyDimensionRegions
512              printf("dst velocity value = %d\n", dstDimCase[gig::dimension_velocity]);              printf("dst velocity value = %d\n", dstDimCase[gig::dimension_velocity]);
513              printf("dst refilled "); fflush(stdout);              printf("dst refilled "); fflush(stdout);
514              #endif              #endif
515              fillDimValues(dstDimValues, dstDimCase, outRgn, true);              fillDimValues(dstDimValues, dstDimCase, outRgn, false);
516              dstDimRgn = outRgn->GetDimensionRegionByValue(dstDimValues);              dstDimRgn = outRgn->GetDimensionRegionByValue(dstDimValues);
517              #if DEBUG_COMBINE_INSTRUMENTS              #if DEBUG_COMBINE_INSTRUMENTS
518              printf("reselected dstDimRgn=%lx\n", (uint64_t)dstDimRgn);              printf("reselected dstDimRgn=%lx\n", (uint64_t)dstDimRgn);
# Line 660  static void combineInstruments(std::vect Line 667  static void combineInstruments(std::vect
667              iTotalZones += (def) ? def->zones : 1;              iTotalZones += (def) ? def->zones : 1;
668          }          }
669          #if DEBUG_COMBINE_INSTRUMENTS          #if DEBUG_COMBINE_INSTRUMENTS
670          printf("Required total zones: %d\n", iTotalZones);          printf("Required total zones: %d, vertical regions: %d\n", iTotalZones, itGroup->second.size());
671          #endif          #endif
672    
673          // create all required dimensions for this output region          // create all required dimensions for this output region
# Line 722  static void combineInstruments(std::vect Line 729  static void combineInstruments(std::vect
729              #if DEBUG_COMBINE_INSTRUMENTS              #if DEBUG_COMBINE_INSTRUMENTS
730              std::cout << "OK" << std::endl << std::flush;              std::cout << "OK" << std::endl << std::flush;
731              #endif              #endif
732            } else {
733                dims.erase(mainDimension);
734          }          }
735    
736          // for the next task we need to have the current RegionGroup to be          // for the next task we need to have the current RegionGroup to be
# Line 803  static void combineInstruments(std::vect Line 812  static void combineInstruments(std::vect
812  // class 'CombineInstrumentsDialog'  // class 'CombineInstrumentsDialog'
813    
814  CombineInstrumentsDialog::CombineInstrumentsDialog(Gtk::Window& parent, gig::File* gig)  CombineInstrumentsDialog::CombineInstrumentsDialog(Gtk::Window& parent, gig::File* gig)
815      : Gtk::Dialog(_("Combine Instruments"), parent, true),      : ManagedDialog(_("Combine Instruments"), parent, true),
816        m_gig(gig), m_fileWasChanged(false), m_newCombinedInstrument(NULL),        m_gig(gig), m_fileWasChanged(false), m_newCombinedInstrument(NULL),
817    #if HAS_GTKMM_STOCK
818        m_cancelButton(Gtk::Stock::CANCEL), m_OKButton(Gtk::Stock::OK),        m_cancelButton(Gtk::Stock::CANCEL), m_OKButton(Gtk::Stock::OK),
819        m_descriptionLabel(), m_tableDimCombo(2, 2), m_comboDimType(),  #else
820          m_cancelButton(_("_Cancel"), true), m_OKButton(_("_OK"), true),
821    #endif
822          m_descriptionLabel(),
823    #if USE_GTKMM_GRID
824          m_tableDimCombo(),
825    #else
826          m_tableDimCombo(2, 2),
827    #endif
828          m_comboDimType(),
829        m_labelDimType(Glib::ustring(_("Combine by Dimension:")) + "  ", Gtk::ALIGN_END)        m_labelDimType(Glib::ustring(_("Combine by Dimension:")) + "  ", Gtk::ALIGN_END)
830  {  {
831        if (!Settings::singleton()->autoRestoreWindowDimension) {
832            set_default_size(500, 600);
833            set_position(Gtk::WIN_POS_MOUSE);
834        }
835    
836        m_scrolledWindow.add(m_treeView);
837        m_scrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
838    
839    #if USE_GTKMM_BOX
840        get_content_area()->pack_start(m_descriptionLabel, Gtk::PACK_SHRINK);
841        get_content_area()->pack_start(m_tableDimCombo, Gtk::PACK_SHRINK);
842        get_content_area()->pack_start(m_scrolledWindow);
843        get_content_area()->pack_start(m_labelOrder, Gtk::PACK_SHRINK);
844        get_content_area()->pack_start(m_iconView, Gtk::PACK_SHRINK);
845        get_content_area()->pack_start(m_buttonBox, Gtk::PACK_SHRINK);
846    #else
847      get_vbox()->pack_start(m_descriptionLabel, Gtk::PACK_SHRINK);      get_vbox()->pack_start(m_descriptionLabel, Gtk::PACK_SHRINK);
848      get_vbox()->pack_start(m_tableDimCombo, Gtk::PACK_SHRINK);      get_vbox()->pack_start(m_tableDimCombo, Gtk::PACK_SHRINK);
849      get_vbox()->pack_start(m_treeView);      get_vbox()->pack_start(m_scrolledWindow);
850        get_vbox()->pack_start(m_labelOrder, Gtk::PACK_SHRINK);
851        get_vbox()->pack_start(m_iconView, Gtk::PACK_SHRINK);
852      get_vbox()->pack_start(m_buttonBox, Gtk::PACK_SHRINK);      get_vbox()->pack_start(m_buttonBox, Gtk::PACK_SHRINK);
853    #endif
854    
855  #if GTKMM_MAJOR_VERSION >= 3  #if GTKMM_MAJOR_VERSION >= 3
856      m_descriptionLabel.set_line_wrap();      m_descriptionLabel.set_line_wrap();
# Line 856  CombineInstrumentsDialog::CombineInstrum Line 894  CombineInstrumentsDialog::CombineInstrum
894          "Use SHIFT + left click or CTRL + left click to select the instruments "          "Use SHIFT + left click or CTRL + left click to select the instruments "
895          "you want to combine."          "you want to combine."
896      ));      ));
897      m_treeView.append_column("Instrument", m_columns.m_col_name);      m_treeView.append_column(_("Nr"), m_columns.m_col_index);
898      m_treeView.set_headers_visible(false);      m_treeView.append_column(_("Instrument"), m_columns.m_col_name);
899        m_treeView.set_headers_visible(true);
900      m_treeView.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);      m_treeView.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
901      m_treeView.get_selection()->signal_changed().connect(      m_treeView.get_selection()->signal_changed().connect(
902          sigc::mem_fun(*this, &CombineInstrumentsDialog::onSelectionChanged)          sigc::mem_fun(*this, &CombineInstrumentsDialog::onSelectionChanged)
# Line 882  CombineInstrumentsDialog::CombineInstrum Line 921  CombineInstrumentsDialog::CombineInstrum
921          Glib::ustring name(gig_to_utf8(instr->pInfo->Name));          Glib::ustring name(gig_to_utf8(instr->pInfo->Name));
922          Gtk::TreeModel::iterator iter = m_refTreeModel->append();          Gtk::TreeModel::iterator iter = m_refTreeModel->append();
923          Gtk::TreeModel::Row row = *iter;          Gtk::TreeModel::Row row = *iter;
924            row[m_columns.m_col_index] = i;
925          row[m_columns.m_col_name] = name;          row[m_columns.m_col_name] = name;
926          row[m_columns.m_col_instr] = instr;          row[m_columns.m_col_instr] = instr;
927      }      }
928    
929        m_refOrderModel = Gtk::ListStore::create(m_orderColumns);
930        m_iconView.set_model(m_refOrderModel);
931        m_iconView.set_tooltip_text(_("Use drag & drop to change the order."));
932        m_iconView.set_markup_column(1);
933        m_iconView.set_selection_mode(Gtk::SELECTION_SINGLE);
934        // force background to retain white also on selections
935        // (this also fixes a bug with GTK 2 which often causes visibility issue
936        //  with the text of the selected item)
937        {
938    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
939            Gdk::Color white;
940    #else
941            Gdk::RGBA white;
942    #endif
943            white.set("#ffffff");
944            GtkWidget* widget = (GtkWidget*) m_iconView.gobj();
945    #if GTK_MAJOR_VERSION < 3
946            gtk_widget_modify_base(widget, GTK_STATE_SELECTED, white.gobj());
947            gtk_widget_modify_base(widget, GTK_STATE_ACTIVE, white.gobj());
948            gtk_widget_modify_bg(widget, GTK_STATE_SELECTED, white.gobj());
949            gtk_widget_modify_bg(widget, GTK_STATE_ACTIVE, white.gobj());
950    #endif
951        }
952    
953        m_labelOrder.set_text(_("Order of the instruments to be combined:"));
954    
955        // establish drag&drop within the instrument tree view, allowing to reorder
956        // the sequence of instruments within the gig file
957        {
958            std::vector<Gtk::TargetEntry> drag_target_instrument;
959            drag_target_instrument.push_back(Gtk::TargetEntry("gig::Instrument"));
960            m_iconView.drag_source_set(drag_target_instrument);
961            m_iconView.drag_dest_set(drag_target_instrument);
962            m_iconView.signal_drag_begin().connect(
963                sigc::mem_fun(*this, &CombineInstrumentsDialog::on_order_drag_begin)
964            );
965            m_iconView.signal_drag_data_get().connect(
966                sigc::mem_fun(*this, &CombineInstrumentsDialog::on_order_drag_data_get)
967            );
968            m_iconView.signal_drag_data_received().connect(
969                sigc::mem_fun(*this, &CombineInstrumentsDialog::on_order_drop_drag_data_received)
970            );
971        }
972    
973      m_buttonBox.set_layout(Gtk::BUTTONBOX_END);      m_buttonBox.set_layout(Gtk::BUTTONBOX_END);
974    #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION > 24)
975        m_buttonBox.set_margin(5);
976    #else
977      m_buttonBox.set_border_width(5);      m_buttonBox.set_border_width(5);
978    #endif
979      m_buttonBox.pack_start(m_cancelButton, Gtk::PACK_SHRINK);      m_buttonBox.pack_start(m_cancelButton, Gtk::PACK_SHRINK);
980      m_buttonBox.pack_start(m_OKButton, Gtk::PACK_SHRINK);      m_buttonBox.pack_start(m_OKButton, Gtk::PACK_SHRINK);
981      m_buttonBox.show();      m_buttonBox.show();
# Line 904  CombineInstrumentsDialog::CombineInstrum Line 992  CombineInstrumentsDialog::CombineInstrum
992          sigc::mem_fun(*this, &CombineInstrumentsDialog::combineSelectedInstruments)          sigc::mem_fun(*this, &CombineInstrumentsDialog::combineSelectedInstruments)
993      );      );
994    
995    #if HAS_GTKMM_SHOW_ALL_CHILDREN
996      show_all_children();      show_all_children();
997    #endif
998    
999        Settings::singleton()->showTooltips.get_proxy().signal_changed().connect(
1000            sigc::mem_fun(*this, &CombineInstrumentsDialog::on_show_tooltips_changed)
1001        );
1002        on_show_tooltips_changed();
1003    
1004      // show a warning to user if he uses a .gig in v2 format      // show a warning to user if he uses a .gig in v2 format
1005      if (gig->pVersion->major < 3) {      if (gig->pVersion->major < 3) {
# Line 917  CombineInstrumentsDialog::CombineInstrum Line 1012  CombineInstrumentsDialog::CombineInstrum
1012          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_WARNING);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_WARNING);
1013          msg.run();          msg.run();
1014      }      }
1015    
1016        // OK button should have focus by default for quick combining with Return key
1017        m_OKButton.grab_focus();
1018    }
1019    
1020    void CombineInstrumentsDialog::on_order_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
1021    {
1022        #if DEBUG_COMBINE_INSTRUMENTS
1023        printf("Drag begin\n");
1024        #endif
1025        first_call_to_drag_data_get = true;
1026    }
1027    
1028    void CombineInstrumentsDialog::on_order_drag_data_get(const Glib::RefPtr<Gdk::DragContext>& context,
1029                                                           Gtk::SelectionData& selection_data, guint, guint)
1030    {
1031        #if DEBUG_COMBINE_INSTRUMENTS
1032        printf("Drag data get\n");
1033        #endif
1034        if (!first_call_to_drag_data_get) return;
1035        first_call_to_drag_data_get = false;
1036    
1037        // get selected source instrument
1038        gig::Instrument* src = NULL;
1039        {
1040            std::vector<Gtk::TreeModel::Path> rows = m_iconView.get_selected_items();
1041            if (!rows.empty()) {
1042                Gtk::TreeModel::iterator it = m_refOrderModel->get_iter(rows[0]);
1043                if (it) {
1044                    Gtk::TreeModel::Row row = *it;
1045                    src = row[m_orderColumns.m_col_instr];
1046                }
1047            }
1048        }
1049        if (!src) {
1050            printf("Drag data get: !src\n");
1051            return;
1052        }
1053        #if DEBUG_COMBINE_INSTRUMENTS
1054        printf("src=%ld\n", (size_t)src);
1055        #endif
1056    
1057        // pass the source gig::Instrument as pointer
1058        selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&src,
1059                           sizeof(src)/*length of data in bytes*/);
1060    }
1061    
1062    void CombineInstrumentsDialog::on_order_drop_drag_data_received(
1063        const Glib::RefPtr<Gdk::DragContext>& context, int x, int y,
1064        const Gtk::SelectionData& selection_data, guint, guint time)
1065    {
1066        #if DEBUG_COMBINE_INSTRUMENTS
1067        printf("Drag data received\n");
1068        #endif
1069        if (!selection_data.get_data()) {
1070            printf("selection_data.get_data() == NULL\n");
1071            return;
1072        }
1073    
1074        gig::Instrument* src = *((gig::Instrument**) selection_data.get_data());
1075        if (!src || selection_data.get_length() != sizeof(gig::Instrument*)) {
1076            printf("!src\n");
1077            return;
1078        }
1079        #if DEBUG_COMBINE_INSTRUMENTS
1080        printf("src=%ld\n", (size_t)src);
1081        #endif
1082    
1083        gig::Instrument* dst = NULL;
1084        {
1085            Gtk::TreeModel::Path path = m_iconView.get_path_at_pos(x, y);
1086            if (!path) return;
1087    
1088            Gtk::TreeModel::iterator iter = m_refOrderModel->get_iter(path);
1089            if (!iter) return;
1090            Gtk::TreeModel::Row row = *iter;
1091            dst = row[m_orderColumns.m_col_instr];
1092        }
1093        if (!dst) {
1094            printf("!dst\n");
1095            return;
1096        }
1097    
1098        #if DEBUG_COMBINE_INSTRUMENTS
1099        printf("dragdrop received src='%s' dst='%s'\n", src->pInfo->Name.c_str(), dst->pInfo->Name.c_str());
1100        #endif
1101    
1102        // swap the two items
1103        typedef Gtk::TreeModel::Children Children;
1104        Children children = m_refOrderModel->children();
1105        Children::iterator itSrc, itDst;
1106        int i = 0, iSrc = -1, iDst = -1;
1107        for (Children::iterator iter = children.begin();
1108             iter != children.end(); ++iter, ++i)
1109        {
1110            Gtk::TreeModel::Row row = *iter;
1111            if (row[m_orderColumns.m_col_instr] == src) {
1112                itSrc = iter;
1113                iSrc  = i;
1114            } else if (row[m_orderColumns.m_col_instr] == dst) {
1115                itDst = iter;
1116                iDst  = i;
1117            }
1118        }
1119        if (itSrc && itDst) {
1120            // swap elements
1121            m_refOrderModel->iter_swap(itSrc, itDst);
1122            // update markup
1123            Gtk::TreeModel::Row rowSrc = *itSrc;
1124            Gtk::TreeModel::Row rowDst = *itDst;
1125            {
1126                Glib::ustring name = rowSrc[m_orderColumns.m_col_name];
1127                Glib::ustring markup =
1128                    "<span foreground='black' background='white'>" + ToString(iDst+1) + ".</span>\n<span foreground='green' background='white'>" + name + "</span>";
1129                rowSrc[m_orderColumns.m_col_markup] = markup;
1130            }
1131            {
1132                Glib::ustring name = rowDst[m_orderColumns.m_col_name];
1133                Glib::ustring markup =
1134                    "<span foreground='black' background='white'>" + ToString(iSrc+1) + ".</span>\n<span foreground='green' background='white'>" + name + "</span>";
1135                rowDst[m_orderColumns.m_col_markup] = markup;
1136            }
1137        }
1138    }
1139    
1140    void CombineInstrumentsDialog::setSelectedInstruments(const std::set<int>& instrumentIndeces) {
1141        typedef Gtk::TreeModel::Children Children;
1142        Children children = m_refTreeModel->children();
1143        for (Children::iterator iter = children.begin();
1144             iter != children.end(); ++iter)
1145        {
1146            Gtk::TreeModel::Row row = *iter;
1147            int index = row[m_columns.m_col_index];
1148            if (instrumentIndeces.count(index))
1149                m_treeView.get_selection()->select(iter);
1150        }
1151        // hack: OK button lost focus after doing the above, it should have focus by default for quick combining with Return key
1152        m_OKButton.grab_focus();
1153  }  }
1154    
1155  void CombineInstrumentsDialog::combineSelectedInstruments() {  void CombineInstrumentsDialog::combineSelectedInstruments() {
1156      std::vector<gig::Instrument*> instruments;      std::vector<gig::Instrument*> instruments;
1157      std::vector<Gtk::TreeModel::Path> v = m_treeView.get_selection()->get_selected_rows();      {
1158      for (uint i = 0; i < v.size(); ++i) {          typedef Gtk::TreeModel::Children Children;
1159          Gtk::TreeModel::iterator it = m_refTreeModel->get_iter(v[i]);          int i = 0;
1160          Gtk::TreeModel::Row row = *it;          Children selection = m_refOrderModel->children();
1161          Glib::ustring name = row[m_columns.m_col_name];          for (Children::iterator it = selection.begin();
1162          gig::Instrument* instrument = row[m_columns.m_col_instr];               it != selection.end(); ++it, ++i)
1163          #if DEBUG_COMBINE_INSTRUMENTS          {
1164          printf("Selection '%s' 0x%lx\n\n", name.c_str(), int64_t((void*)instrument));              Gtk::TreeModel::Row row = *it;
1165          #endif              Glib::ustring name = row[m_orderColumns.m_col_name];
1166          instruments.push_back(instrument);              gig::Instrument* instrument = row[m_orderColumns.m_col_instr];
1167                #if DEBUG_COMBINE_INSTRUMENTS
1168                printf("Selection %d. '%s' %p\n\n", (i+1), name.c_str(), instrument);
1169                #endif
1170                instruments.push_back(instrument);
1171            }
1172      }      }
1173    
1174      g_warnings.clear();      g_warnings.clear();
# Line 947  void CombineInstrumentsDialog::combineSe Line 1185  void CombineInstrumentsDialog::combineSe
1185              mainDimension = static_cast<gig::dimension_t>(iTypeID);              mainDimension = static_cast<gig::dimension_t>(iTypeID);
1186          }          }
1187    
1188          // now start the actual cobination task ...          // now start the actual combination task ...
1189          combineInstruments(instruments, m_gig, m_newCombinedInstrument, mainDimension);          combineInstruments(instruments, m_gig, m_newCombinedInstrument, mainDimension);
1190      } catch (RIFF::Exception e) {;      } catch (RIFF::Exception e) {;
1191          Gtk::MessageDialog msg(*this, e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, e.Message, false, Gtk::MESSAGE_ERROR);
# Line 987  void CombineInstrumentsDialog::combineSe Line 1225  void CombineInstrumentsDialog::combineSe
1225  void CombineInstrumentsDialog::onSelectionChanged() {  void CombineInstrumentsDialog::onSelectionChanged() {
1226      std::vector<Gtk::TreeModel::Path> v = m_treeView.get_selection()->get_selected_rows();      std::vector<Gtk::TreeModel::Path> v = m_treeView.get_selection()->get_selected_rows();
1227      m_OKButton.set_sensitive(v.size() >= 2);      m_OKButton.set_sensitive(v.size() >= 2);
1228    
1229        typedef Gtk::TreeModel::Children Children;
1230    
1231        // update horizontal selection list (icon view) ...
1232    
1233        // remove items which are not part of the new selection anymore
1234        {
1235            Children allOrdered = m_refOrderModel->children();
1236            for (Children::iterator itOrder = allOrdered.begin();
1237                 itOrder != allOrdered.end(); )
1238            {
1239                Gtk::TreeModel::Row rowOrder = *itOrder;
1240                gig::Instrument* instr = rowOrder[m_orderColumns.m_col_instr];
1241                for (uint i = 0; i < v.size(); ++i) {
1242                    Gtk::TreeModel::iterator itSel = m_refTreeModel->get_iter(v[i]);
1243                    Gtk::TreeModel::Row rowSel = *itSel;
1244                    if (rowSel[m_columns.m_col_instr] == instr)
1245                        goto nextOrderedItem;
1246                }
1247                goto removeOrderedItem;
1248            nextOrderedItem:
1249                ++itOrder;
1250                continue;
1251            removeOrderedItem:
1252                // postfix increment here to avoid iterator invalidation
1253                m_refOrderModel->erase(itOrder++);
1254            }
1255        }
1256    
1257        // add items newly added to the selection
1258        for (uint i = 0; i < v.size(); ++i) {
1259            Gtk::TreeModel::iterator itSel = m_refTreeModel->get_iter(v[i]);
1260            Gtk::TreeModel::Row rowSel = *itSel;
1261            gig::Instrument* instr = rowSel[m_columns.m_col_instr];
1262            Children allOrdered = m_refOrderModel->children();
1263            for (Children::iterator itOrder = allOrdered.begin();
1264                 itOrder != allOrdered.end(); ++itOrder)
1265            {
1266                Gtk::TreeModel::Row rowOrder = *itOrder;
1267                if (rowOrder[m_orderColumns.m_col_instr] == instr)
1268                    goto nextSelectionItem;
1269            }
1270            goto addNewSelectionItem;
1271        nextSelectionItem:
1272            continue;
1273        addNewSelectionItem:
1274            Glib::ustring name = gig_to_utf8(instr->pInfo->Name);
1275            Gtk::TreeModel::iterator iterOrder = m_refOrderModel->append();
1276            Gtk::TreeModel::Row rowOrder = *iterOrder;
1277            rowOrder[m_orderColumns.m_col_name] = name;
1278            rowOrder[m_orderColumns.m_col_instr] = instr;
1279        }
1280    
1281        // update markup
1282        {
1283            int i = 0;
1284            Children allOrdered = m_refOrderModel->children();
1285            for (Children::iterator itOrder = allOrdered.begin();
1286                 itOrder != allOrdered.end(); ++itOrder, ++i)
1287            {
1288                Gtk::TreeModel::Row rowOrder = *itOrder;
1289                Glib::ustring name = rowOrder[m_orderColumns.m_col_name];
1290                Glib::ustring markup =
1291                    "<span foreground='black' background='white'>" + ToString(i+1) + ".</span>\n<span foreground='green' background='white'>" + name + "</span>";
1292                rowOrder[m_orderColumns.m_col_markup] = markup;
1293            }
1294        }
1295    }
1296    
1297    void CombineInstrumentsDialog::on_show_tooltips_changed() {
1298        const bool b = Settings::singleton()->showTooltips;
1299    
1300        m_treeView.set_has_tooltip(b);
1301        m_iconView.set_has_tooltip(b);
1302    
1303        set_has_tooltip(b);
1304  }  }
1305    
1306  bool CombineInstrumentsDialog::fileWasChanged() const {  bool CombineInstrumentsDialog::fileWasChanged() const {

Legend:
Removed from v.2579  
changed lines
  Added in v.3782

  ViewVC Help
Powered by ViewVC