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

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

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

revision 2844 by persson, Sun Sep 20 08:49:40 2015 UTC revision 3105 by schoenebeck, Fri Feb 10 18:40:26 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2015 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 23  Line 23 
23  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
24  #include <gdkmm/general.h>  #include <gdkmm/general.h>
25  #include <glibmm/stringutils.h>  #include <glibmm/stringutils.h>
 #include <gtkmm/stock.h>  
26  #include <glibmm/ustring.h>  #include <glibmm/ustring.h>
27  #include <gtkmm/messagedialog.h>  #include <gtkmm/messagedialog.h>
28    #include <assert.h>
29    
30  #include "global.h"  #include "global.h"
31    
# Line 89  DimRegionChooser::DimRegionChooser(Gtk:: Line 89  DimRegionChooser::DimRegionChooser(Gtk::
89      cursor_is_resize = false;      cursor_is_resize = false;
90      h = 24;      h = 24;
91      multiSelectKeyDown = false;      multiSelectKeyDown = false;
92        modifybothchannels = modifyalldimregs = modifybothchannels = false;
93      set_can_focus();      set_can_focus();
94    
95        const Glib::ustring txtUseCheckBoxAllRegions =
96            _("Use checkbox 'all regions' to control whether this should apply to all regions.");
97    
98      actionGroup = Gtk::ActionGroup::create();      actionGroup = Gtk::ActionGroup::create();
99        actionSplitDimZone = Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
100        actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
101      actionGroup->add(      actionGroup->add(
102          Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone")),          actionSplitDimZone,
103          sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)          sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
104      );      );
105        actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
106        actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
107      actionGroup->add(      actionGroup->add(
108          Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone")),          actionDeleteDimZone,
109          sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)          sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
110      );      );
111    
# Line 142  DimRegionChooser::~DimRegionChooser() Line 150  DimRegionChooser::~DimRegionChooser()
150  {  {
151  }  }
152    
153    void DimRegionChooser::setModifyBothChannels(bool b) {
154        modifybothchannels = b;
155    }
156    
157    void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
158        modifyalldimregs = b;
159    }
160    
161    void DimRegionChooser::setModifyAllRegions(bool b) {
162        modifyallregions = b;
163    
164        actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
165        actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
166    }
167    
168  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
169  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
170  {  {
# Line 508  void DimRegionChooser::get_dimregions(co Line 531  void DimRegionChooser::get_dimregions(co
531    
532  void DimRegionChooser::update_after_resize()  void DimRegionChooser::update_after_resize()
533  {  {
534      if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {      const uint8_t upperLimit = resize.pos - 1;
535        gig::Instrument* instr = (gig::Instrument*)region->GetParent();
536    
537          int bitpos = 0;      int bitpos = 0;
538          for (int j = 0 ; j < resize.dimension ; j++) {      for (int j = 0 ; j < resize.dimension ; j++) {
539              bitpos += region->pDimensionDefinitions[j].bits;          bitpos += region->pDimensionDefinitions[j].bits;
540          }      }
541    
542        const int stereobitpos =
543            (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
544    
545        // the velocity dimension must be handled differently than all other
546        // dimension types, because
547        // 1. it is currently the only dimension type which allows different zone
548        //    sizes for different cases
549        // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
550        if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
551          int mask =          int mask =
552              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
553          int c = maindimregno & mask; // mask away this dimension          int c = maindimregno & mask; // mask away this dimension
# Line 539  void DimRegionChooser::update_after_resi Line 573  void DimRegionChooser::update_after_resi
573              }              }
574          }          }
575    
576          gig::DimensionRegion* d = region->pDimensionRegions[c + resize.offset];          int index = c + (resize.zone << bitpos);
577            gig::DimensionRegion* d = region->pDimensionRegions[index];
578          // update both v2 and v3 values          // update both v2 and v3 values
579          d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;          d->DimensionUpperLimits[resize.dimension] = upperLimit;
580          d->VelocityUpperLimit = resize.pos - 1;          d->VelocityUpperLimit = upperLimit;
581            if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
582                gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
583                d->DimensionUpperLimits[resize.dimension] = upperLimit;
584                d->VelocityUpperLimit = upperLimit;
585            }
586    
587            if (modifyalldimregs) {
588                gig::Region* rgn = NULL;
589                for (int key = 0; key < 128; ++key) {
590                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
591                    rgn = instr->GetRegion(key);
592                    if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
593                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
594                    if (!dimdef) continue;
595                    if (dimdef->zones != resize.dimensionDef.zones) continue;
596                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
597                    assert(iDim >= 0 && iDim < rgn->Dimensions);
598    
599                    // the dimension layout might be completely different in this
600                    // region, so we have to recalculate bitpos etc for this region
601                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
602                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
603                    const int selection = resize.zone << bitpos;
604    
605                    // primitive and inefficient loop implementation, however due to
606                    // this circumstance the loop code is much simpler, and its lack
607                    // of runtime efficiency should not be notable in practice
608                    for (int idr = 0; idr < 256; ++idr) {
609                        const int index = (idr & stencil) | selection;
610                        assert(index >= 0 && index < 256);
611                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
612                        if (!dr) continue;
613                        dr->DimensionUpperLimits[iDim] = upperLimit;
614                        d->VelocityUpperLimit = upperLimit;
615                    }
616                }
617            } else if (modifyallregions) { // implies modifyalldimregs is false ...
618                // resolve the precise case we need to modify for all other regions
619                DimensionCase dimCase = dimensionCaseOf(d);
620                // apply the velocity upper limit change to that resolved dim case
621                // of all regions ...
622                gig::Region* rgn = NULL;
623                for (int key = 0; key < 128; ++key) {
624                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
625                    rgn = instr->GetRegion(key);
626                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
627                    if (!dimdef) continue;
628                    if (dimdef->zones != resize.dimensionDef.zones) continue;
629                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
630                    assert(iDim >= 0 && iDim < rgn->Dimensions);
631    
632                    std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
633                    for (int i = 0; i < dimrgns.size(); ++i) {
634                        gig::DimensionRegion* dr = dimrgns[i];
635                        dr->DimensionUpperLimits[iDim] = upperLimit;
636                        dr->VelocityUpperLimit = upperLimit;
637                    }
638                }
639            }
640      } else {      } else {
641          for (int i = 0 ; i < region->DimensionRegions ; ) {          for (int i = 0 ; i < region->DimensionRegions ; ) {
   
642              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
643                  // the dimension didn't previously have custom                  // the dimension didn't previously have custom
644                  // limits, so we have to set default limits for                  // limits, so we have to set default limits for
645                  // all the dimension regions                  // all the dimension regions
                 int bitpos = 0;  
                 for (int j = 0 ; j < resize.dimension ; j++) {  
                     bitpos += region->pDimensionDefinitions[j].bits;  
                 }  
646                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
647    
648                  for (int j = 0 ; j < nbZones ; j++) {                  for (int j = 0 ; j < nbZones ; j++) {
# Line 562  void DimRegionChooser::update_after_resi Line 650  void DimRegionChooser::update_after_resi
650                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
651                  }                  }
652              }              }
653              gig::DimensionRegion* d = region->pDimensionRegions[i + resize.offset];              int index = i + (resize.zone << bitpos);
654              d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              gig::DimensionRegion* d = region->pDimensionRegions[index];
655                d->DimensionUpperLimits[resize.dimension] = upperLimit;
656    #if 0       // the following is currently not necessary, because ATM the gig format uses for all dimension types except of the veleocity dimension the same zone sizes for all cases
657                if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
658                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
659                    d->DimensionUpperLimits[resize.dimension] = upperLimit;
660                }
661    #endif
662              int bitpos = 0;              int bitpos = 0;
663              int j;              int j;
664              for (j = 0 ; j < region->Dimensions ; j++) {              for (j = 0 ; j < region->Dimensions ; j++) {
# Line 578  void DimRegionChooser::update_after_resi Line 672  void DimRegionChooser::update_after_resi
672              if (j == region->Dimensions) break;              if (j == region->Dimensions) break;
673              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
674          }          }
675    
676            if (modifyallregions) { // TODO: this code block could be merged with the similar (and more generalized) code block of the velocity dimension above
677                gig::Region* rgn = NULL;
678                for (int key = 0; key < 128; ++key) {
679                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
680                    rgn = instr->GetRegion(key);
681                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
682                    if (!dimdef) continue;
683                    if (dimdef->zones != resize.dimensionDef.zones) continue;
684                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
685                    assert(iDim >= 0 && iDim < rgn->Dimensions);
686    
687                    // the dimension layout might be completely different in this
688                    // region, so we have to recalculate bitpos etc for this region
689                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
690                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
691                    const int selection = resize.zone << bitpos;
692    
693                    // this loop implementation is less efficient than the above's
694                    // loop implementation (which skips unnecessary dimension regions)
695                    // however this code is much simpler, and its lack of runtime
696                    // efficiency should not be notable in practice
697                    for (int idr = 0; idr < 256; ++idr) {
698                        const int index = (idr & stencil) | selection;
699                        assert(index >= 0 && index < 256);
700                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
701                        if (!dr) continue;
702                        dr->DimensionUpperLimits[iDim] = upperLimit;
703                    }
704                }
705            }
706      }      }
707  }  }
708    
# Line 806  bool DimRegionChooser::is_in_resize_zone Line 931  bool DimRegionChooser::is_in_resize_zone
931                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
932                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
933                      resize.dimension = dim;                      resize.dimension = dim;
934                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
935                        resize.zone = iZone;
936                      resize.pos = limit;                      resize.pos = limit;
937                      resize.min = prev_limit;                      resize.min = prev_limit;
938    
# Line 892  bool DimRegionChooser::on_focus(Gtk::Dir Line 1018  bool DimRegionChooser::on_focus(Gtk::Dir
1018  void DimRegionChooser::split_dimension_zone() {      void DimRegionChooser::split_dimension_zone() {    
1019      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1020      try {      try {
1021          region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);          if (!modifyallregions) {
1022                region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1023            } else {
1024                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1025                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1026                assert(pMaindimdef != NULL);
1027                // retain structure by value since the original region will be
1028                // modified in the loop below as well
1029                gig::dimension_def_t maindimdef = *pMaindimdef;
1030                std::vector<gig::Region*> ignoredAll;
1031                std::vector<gig::Region*> ignoredMinor;
1032                std::vector<gig::Region*> ignoredCritical;
1033                gig::Region* rgn = NULL;
1034                for (int key = 0; key < 128; ++key) {
1035                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1036                    rgn = instr->GetRegion(key);
1037    
1038                    // ignore all regions which do not exactly match the dimension
1039                    // layout of the selected region where this operation was emitted
1040                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1041                    if (!dimdef) {
1042                        ignoredAll.push_back(rgn);
1043                        ignoredMinor.push_back(rgn);
1044                        continue;
1045                    }
1046                    if (dimdef->zones != maindimdef.zones) {
1047                        ignoredAll.push_back(rgn);
1048                        ignoredCritical.push_back(rgn);
1049                        continue;
1050                    }
1051    
1052                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1053                }
1054                if (!ignoredAll.empty()) {
1055                    Glib::ustring txt;
1056                    if (ignoredCritical.empty())
1057                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1058                    else if (ignoredMinor.empty())
1059                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1060                    else
1061                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1062                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1063                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1064                    Gtk::MessageDialog msg(txt, false, type);
1065                    msg.run();
1066                }
1067            }
1068      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1069          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1070          msg.run();          msg.run();
# Line 907  void DimRegionChooser::split_dimension_z Line 1079  void DimRegionChooser::split_dimension_z
1079  void DimRegionChooser::delete_dimension_zone() {  void DimRegionChooser::delete_dimension_zone() {
1080      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1081      try {      try {
1082          region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);          if (!modifyallregions) {
1083                region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1084            } else {
1085                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1086                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1087                assert(pMaindimdef != NULL);
1088                // retain structure by value since the original region will be
1089                // modified in the loop below as well
1090                gig::dimension_def_t maindimdef = *pMaindimdef;
1091                std::vector<gig::Region*> ignoredAll;
1092                std::vector<gig::Region*> ignoredMinor;
1093                std::vector<gig::Region*> ignoredCritical;
1094                gig::Region* rgn = NULL;
1095                for (int key = 0; key < 128; ++key) {
1096                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1097                    rgn = instr->GetRegion(key);
1098    
1099                    // ignore all regions which do not exactly match the dimension
1100                    // layout of the selected region where this operation was emitted
1101                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1102                    if (!dimdef) {
1103                        ignoredAll.push_back(rgn);
1104                        ignoredMinor.push_back(rgn);
1105                        continue;
1106                    }
1107                    if (dimdef->zones != maindimdef.zones) {
1108                        ignoredAll.push_back(rgn);
1109                        ignoredCritical.push_back(rgn);
1110                        continue;
1111                    }
1112    
1113                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1114                }
1115                if (!ignoredAll.empty()) {
1116                    Glib::ustring txt;
1117                    if (ignoredCritical.empty())
1118                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1119                    else if (ignoredMinor.empty())
1120                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1121                    else
1122                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1123                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1124                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1125                    Gtk::MessageDialog msg(txt, false, type);
1126                    msg.run();
1127                }
1128            }
1129      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1130          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1131          msg.run();          msg.run();

Legend:
Removed from v.2844  
changed lines
  Added in v.3105

  ViewVC Help
Powered by ViewVC