/[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 3147 by schoenebeck, Wed May 3 21:23:16 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 20  Line 20 
20  #include <gtkmm/box.h>  #include <gtkmm/box.h>
21  #include "dimregionchooser.h"  #include "dimregionchooser.h"
22  #include <cairomm/context.h>  #include <cairomm/context.h>
23    #include <cairomm/surface.h>
24  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
25  #include <gdkmm/general.h>  #include <gdkmm/general.h>
26  #include <glibmm/stringutils.h>  #include <glibmm/stringutils.h>
 #include <gtkmm/stock.h>  
27  #include <glibmm/ustring.h>  #include <glibmm/ustring.h>
28  #include <gtkmm/messagedialog.h>  #include <gtkmm/messagedialog.h>
29    #include <assert.h>
30    
31  #include "global.h"  #include "global.h"
32    #include "gfx/builtinpix.h"
33    
34  // taken from gdk/gdkkeysyms.h  //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
35  // (define on demand, to avoid unnecessary dev lib package build dependency)  static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
36  #ifndef GDK_KEY_Control_L      DimensionCase dimCase;
 # define GDK_KEY_Control_L 0xffe3  
 #endif  
 #ifndef GDK_KEY_Control_R  
 # define GDK_KEY_Control_R 0xffe4  
 #endif  
   
 static std::map<gig::dimension_t,int> caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {  
     std::map<gig::dimension_t,int> dimCase;  
37      if (!dr) {      if (!dr) {
38          *isValidZone = false;          *isValidZone = false;
39          return dimCase;          return dimCase;
# Line 57  static std::map<gig::dimension_t,int> ca Line 51  static std::map<gig::dimension_t,int> ca
51      if (drIndex == 256) {      if (drIndex == 256) {
52          fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");          fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
53          *isValidZone = false;          *isValidZone = false;
54          return std::map<gig::dimension_t,int>();          return DimensionCase();
55      }      }
56    
57      for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {      for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
# Line 68  static std::map<gig::dimension_t,int> ca Line 62  static std::map<gig::dimension_t,int> ca
62          // there are also DimensionRegion objects of unused zones, skip them          // there are also DimensionRegion objects of unused zones, skip them
63          if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {          if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
64              *isValidZone = false;              *isValidZone = false;
65              return std::map<gig::dimension_t,int>();              return DimensionCase();
66          }          }
67      }      }
68    
# Line 77  static std::map<gig::dimension_t,int> ca Line 71  static std::map<gig::dimension_t,int> ca
71  }  }
72    
73  DimRegionChooser::DimRegionChooser(Gtk::Window& window) :  DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
74      red("#8070ff"),      red("#ff476e"),
75        blue("#4796ff"),
76      black("black"),      black("black"),
77      white("white")      white("white")
78  {  {
79        // make sure blue hatched pattern pixmap is loaded
80        loadBuiltInPix();
81    
82        // create blue hatched pattern
83        {
84            const int width = blueHatchedPattern->get_width();
85            const int height = blueHatchedPattern->get_height();
86            const int stride = blueHatchedPattern->get_rowstride();
87    
88            // manually convert from RGBA to ARGB
89            this->blueHatchedPatternARGB = blueHatchedPattern->copy();
90            const int pixelSize = stride / width;
91            const int totalPixels = width * height;
92            assert(pixelSize == 4);
93            unsigned char* ptr = this->blueHatchedPatternARGB->get_pixels();
94            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
95                const unsigned char r = ptr[0];
96                const unsigned char g = ptr[1];
97                const unsigned char b = ptr[2];
98                const unsigned char a = ptr[3];
99                ptr[0] = b;
100                ptr[1] = g;
101                ptr[2] = r;
102                ptr[3] = a;
103            }
104    
105            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
106                this->blueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
107            );
108            this->blueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
109            this->blueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
110        }
111    
112        // create gray blue hatched pattern
113        {
114            const int width = grayBlueHatchedPattern->get_width();
115            const int height = grayBlueHatchedPattern->get_height();
116            const int stride = grayBlueHatchedPattern->get_rowstride();
117    
118            // manually convert from RGBA to ARGB
119            this->grayBlueHatchedPatternARGB = grayBlueHatchedPattern->copy();
120            const int pixelSize = stride / width;
121            const int totalPixels = width * height;
122            assert(pixelSize == 4);
123            unsigned char* ptr = this->grayBlueHatchedPatternARGB->get_pixels();
124            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
125                const unsigned char r = ptr[0];
126                const unsigned char g = ptr[1];
127                const unsigned char b = ptr[2];
128                const unsigned char a = ptr[3];
129                ptr[0] = b;
130                ptr[1] = g;
131                ptr[2] = r;
132                ptr[3] = a;
133            }
134    
135            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
136                this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
137            );
138            this->grayBlueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
139            this->grayBlueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
140        }
141    
142      instrument = 0;      instrument = 0;
143      region = 0;      region = 0;
144      maindimregno = -1;      maindimregno = -1;
145        maindimtype = gig::dimension_none; // initialize with invalid dimension type
146      focus_line = 0;      focus_line = 0;
147      resize.active = false;      resize.active = false;
148      cursor_is_resize = false;      cursor_is_resize = false;
149      h = 24;      h = 24;
150      multiSelectKeyDown = false;      multiSelectKeyDown = false;
151        primaryKeyDown = false;
152        shiftKeyDown = false;
153        modifybothchannels = modifyalldimregs = modifybothchannels = false;
154      set_can_focus();      set_can_focus();
155    
156        const Glib::ustring txtUseCheckBoxAllRegions =
157            _("Use checkbox 'all regions' to control whether this should apply to all regions.");
158    
159      actionGroup = Gtk::ActionGroup::create();      actionGroup = Gtk::ActionGroup::create();
160        actionSplitDimZone = Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
161        actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
162      actionGroup->add(      actionGroup->add(
163          Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone")),          actionSplitDimZone,
164          sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)          sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
165      );      );
166        actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
167        actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
168      actionGroup->add(      actionGroup->add(
169          Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone")),          actionDeleteDimZone,
170          sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)          sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
171      );      );
172    
# Line 142  DimRegionChooser::~DimRegionChooser() Line 211  DimRegionChooser::~DimRegionChooser()
211  {  {
212  }  }
213    
214    void DimRegionChooser::setModifyBothChannels(bool b) {
215        modifybothchannels = b;
216        // redraw required parts
217        queue_draw();
218    }
219    
220    void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
221        modifyalldimregs = b;
222        // redraw required parts
223        queue_draw();
224    }
225    
226    void DimRegionChooser::setModifyAllRegions(bool b) {
227        modifyallregions = b;
228    
229        actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
230        actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
231    
232        // redraw required parts
233        queue_draw();
234    }
235    
236  #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
237  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
238  {  {
# Line 230  bool DimRegionChooser::on_draw(const Cai Line 321  bool DimRegionChooser::on_draw(const Cai
321                      dstr = dstrbuf;                      dstr = dstrbuf;
322                      break;                      break;
323                  }                  }
                 layout->set_text(dstr);  
324    
325                    // Since bold font yields in larger label width, we first always
326                    // set the bold text variant, retrieve its dimensions (as worst
327                    // case dimensions of the label) ...
328                    layout->set_markup("<b>" + Glib::ustring(dstr) + "</b>");
329                  Pango::Rectangle rectangle = layout->get_logical_extents();                  Pango::Rectangle rectangle = layout->get_logical_extents();
330                    // ... and then reset the label to regular font style in case
331                    // the line is not selected. Otherwise the right hand side
332                    // actual dimension zones would jump around on selection change.
333                    bool isSelectedLine = (focus_line == i);
334                    if (!isSelectedLine)
335                        layout->set_markup(dstr);
336    
337                  double text_w = double(rectangle.get_width()) / Pango::SCALE;                  double text_w = double(rectangle.get_width()) / Pango::SCALE;
338                  if (text_w > maxwidth) maxwidth = text_w;                  if (text_w > maxwidth) maxwidth = text_w;
339    
# Line 339  bool DimRegionChooser::on_draw(const Cai Line 440  bool DimRegionChooser::on_draw(const Cai
440    
441                          // draw fill for zone                          // draw fill for zone
442                          bool isSelectedZone = this->dimzones[dimension].count(j);                          bool isSelectedZone = this->dimzones[dimension].count(j);
443                          Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);                          bool isMainSelection =
444                                this->maindimcase.find(dimension) != this->maindimcase.end() &&
445                                this->maindimcase[dimension] == j;
446                            bool isCheckBoxSelected =
447                                modifyalldimregs ||
448                                (modifybothchannels &&
449                                    dimension == gig::dimension_samplechannel);
450                            if (isMainSelection)
451                                Gdk::Cairo::set_source_rgba(cr, blue);
452                            else if (isSelectedZone)
453                                cr->set_source(blueHatchedSurfacePattern);
454                            else if (isCheckBoxSelected)
455                                cr->set_source(grayBlueHatchedSurfacePattern);
456                            else
457                                Gdk::Cairo::set_source_rgba(cr, white);
458    
459                          cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);                          cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
460                          cr->fill();                          cr->fill();
461    
# Line 397  bool DimRegionChooser::on_draw(const Cai Line 513  bool DimRegionChooser::on_draw(const Cai
513                          if (j != 0) {                          if (j != 0) {
514                              // draw fill for zone                              // draw fill for zone
515                              bool isSelectedZone = this->dimzones[dimension].count(j-1);                              bool isSelectedZone = this->dimzones[dimension].count(j-1);
516                              Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);                              bool isMainSelection =
517                                    this->maindimcase.find(dimension) != this->maindimcase.end() &&
518                                    this->maindimcase[dimension] == (j-1);
519                                bool isCheckBoxSelected =
520                                    modifyalldimregs ||
521                                    (modifybothchannels &&
522                                        dimension == gig::dimension_samplechannel);
523                                if (isMainSelection)
524                                    Gdk::Cairo::set_source_rgba(cr, blue);
525                                else if (isSelectedZone)
526                                    cr->set_source(blueHatchedSurfacePattern);
527                                else if (isCheckBoxSelected)
528                                    cr->set_source(grayBlueHatchedSurfacePattern);
529                                else
530                                    Gdk::Cairo::set_source_rgba(cr, white);
531                              cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);                              cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
532                              cr->fill();                              cr->fill();
533    
# Line 508  void DimRegionChooser::get_dimregions(co Line 638  void DimRegionChooser::get_dimregions(co
638    
639  void DimRegionChooser::update_after_resize()  void DimRegionChooser::update_after_resize()
640  {  {
641      if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {      const uint8_t upperLimit = resize.pos - 1;
642        gig::Instrument* instr = (gig::Instrument*)region->GetParent();
643    
644          int bitpos = 0;      int bitpos = 0;
645          for (int j = 0 ; j < resize.dimension ; j++) {      for (int j = 0 ; j < resize.dimension ; j++) {
646              bitpos += region->pDimensionDefinitions[j].bits;          bitpos += region->pDimensionDefinitions[j].bits;
647          }      }
648    
649        const int stereobitpos =
650            (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
651    
652        // the velocity dimension must be handled differently than all other
653        // dimension types, because
654        // 1. it is currently the only dimension type which allows different zone
655        //    sizes for different cases
656        // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
657        if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
658          int mask =          int mask =
659              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
660          int c = maindimregno & mask; // mask away this dimension          int c = maindimregno & mask; // mask away this dimension
# Line 539  void DimRegionChooser::update_after_resi Line 680  void DimRegionChooser::update_after_resi
680              }              }
681          }          }
682    
683          gig::DimensionRegion* d = region->pDimensionRegions[c + resize.offset];          int index = c + (resize.zone << bitpos);
684            gig::DimensionRegion* d = region->pDimensionRegions[index];
685          // update both v2 and v3 values          // update both v2 and v3 values
686          d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;          d->DimensionUpperLimits[resize.dimension] = upperLimit;
687          d->VelocityUpperLimit = resize.pos - 1;          d->VelocityUpperLimit = upperLimit;
688            if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
689                gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
690                d->DimensionUpperLimits[resize.dimension] = upperLimit;
691                d->VelocityUpperLimit = upperLimit;
692            }
693    
694            if (modifyalldimregs) {
695                gig::Region* rgn = NULL;
696                for (int key = 0; key < 128; ++key) {
697                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
698                    rgn = instr->GetRegion(key);
699                    if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
700                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
701                    if (!dimdef) continue;
702                    if (dimdef->zones != resize.dimensionDef.zones) continue;
703                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
704                    assert(iDim >= 0 && iDim < rgn->Dimensions);
705    
706                    // the dimension layout might be completely different in this
707                    // region, so we have to recalculate bitpos etc for this region
708                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
709                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
710                    const int selection = resize.zone << bitpos;
711    
712                    // primitive and inefficient loop implementation, however due to
713                    // this circumstance the loop code is much simpler, and its lack
714                    // of runtime efficiency should not be notable in practice
715                    for (int idr = 0; idr < 256; ++idr) {
716                        const int index = (idr & stencil) | selection;
717                        assert(index >= 0 && index < 256);
718                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
719                        if (!dr) continue;
720                        dr->DimensionUpperLimits[iDim] = upperLimit;
721                        d->VelocityUpperLimit = upperLimit;
722                    }
723                }
724            } else if (modifyallregions) { // implies modifyalldimregs is false ...
725                // resolve the precise case we need to modify for all other regions
726                DimensionCase dimCase = dimensionCaseOf(d);
727                // apply the velocity upper limit change to that resolved dim case
728                // of all regions ...
729                gig::Region* rgn = NULL;
730                for (int key = 0; key < 128; ++key) {
731                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
732                    rgn = instr->GetRegion(key);
733                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
734                    if (!dimdef) continue;
735                    if (dimdef->zones != resize.dimensionDef.zones) continue;
736                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
737                    assert(iDim >= 0 && iDim < rgn->Dimensions);
738    
739                    std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
740                    for (int i = 0; i < dimrgns.size(); ++i) {
741                        gig::DimensionRegion* dr = dimrgns[i];
742                        dr->DimensionUpperLimits[iDim] = upperLimit;
743                        dr->VelocityUpperLimit = upperLimit;
744                    }
745                }
746            }
747      } else {      } else {
748          for (int i = 0 ; i < region->DimensionRegions ; ) {          for (int i = 0 ; i < region->DimensionRegions ; ) {
   
749              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
750                  // the dimension didn't previously have custom                  // the dimension didn't previously have custom
751                  // limits, so we have to set default limits for                  // limits, so we have to set default limits for
752                  // all the dimension regions                  // all the dimension regions
                 int bitpos = 0;  
                 for (int j = 0 ; j < resize.dimension ; j++) {  
                     bitpos += region->pDimensionDefinitions[j].bits;  
                 }  
753                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
754    
755                  for (int j = 0 ; j < nbZones ; j++) {                  for (int j = 0 ; j < nbZones ; j++) {
# Line 562  void DimRegionChooser::update_after_resi Line 757  void DimRegionChooser::update_after_resi
757                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
758                  }                  }
759              }              }
760              gig::DimensionRegion* d = region->pDimensionRegions[i + resize.offset];              int index = i + (resize.zone << bitpos);
761              d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              gig::DimensionRegion* d = region->pDimensionRegions[index];
762                d->DimensionUpperLimits[resize.dimension] = upperLimit;
763    #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
764                if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
765                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
766                    d->DimensionUpperLimits[resize.dimension] = upperLimit;
767                }
768    #endif
769              int bitpos = 0;              int bitpos = 0;
770              int j;              int j;
771              for (j = 0 ; j < region->Dimensions ; j++) {              for (j = 0 ; j < region->Dimensions ; j++) {
# Line 578  void DimRegionChooser::update_after_resi Line 779  void DimRegionChooser::update_after_resi
779              if (j == region->Dimensions) break;              if (j == region->Dimensions) break;
780              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
781          }          }
782    
783            if (modifyallregions) { // TODO: this code block could be merged with the similar (and more generalized) code block of the velocity dimension above
784                gig::Region* rgn = NULL;
785                for (int key = 0; key < 128; ++key) {
786                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
787                    rgn = instr->GetRegion(key);
788                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
789                    if (!dimdef) continue;
790                    if (dimdef->zones != resize.dimensionDef.zones) continue;
791                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
792                    assert(iDim >= 0 && iDim < rgn->Dimensions);
793    
794                    // the dimension layout might be completely different in this
795                    // region, so we have to recalculate bitpos etc for this region
796                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
797                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
798                    const int selection = resize.zone << bitpos;
799    
800                    // this loop implementation is less efficient than the above's
801                    // loop implementation (which skips unnecessary dimension regions)
802                    // however this code is much simpler, and its lack of runtime
803                    // efficiency should not be notable in practice
804                    for (int idr = 0; idr < 256; ++idr) {
805                        const int index = (idr & stencil) | selection;
806                        assert(index >= 0 && index < 256);
807                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
808                        if (!dr) continue;
809                        dr->DimensionUpperLimits[iDim] = upperLimit;
810                    }
811                }
812            }
813      }      }
814  }  }
815    
# Line 806  bool DimRegionChooser::is_in_resize_zone Line 1038  bool DimRegionChooser::is_in_resize_zone
1038                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
1039                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
1040                      resize.dimension = dim;                      resize.dimension = dim;
1041                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
1042                        resize.zone = iZone;
1043                      resize.pos = limit;                      resize.pos = limit;
1044                      resize.min = prev_limit;                      resize.min = prev_limit;
1045    
# Line 892  bool DimRegionChooser::on_focus(Gtk::Dir Line 1125  bool DimRegionChooser::on_focus(Gtk::Dir
1125  void DimRegionChooser::split_dimension_zone() {      void DimRegionChooser::split_dimension_zone() {    
1126      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1127      try {      try {
1128          region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);          if (!modifyallregions) {
1129                region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1130            } else {
1131                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1132                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1133                assert(pMaindimdef != NULL);
1134                // retain structure by value since the original region will be
1135                // modified in the loop below as well
1136                gig::dimension_def_t maindimdef = *pMaindimdef;
1137                std::vector<gig::Region*> ignoredAll;
1138                std::vector<gig::Region*> ignoredMinor;
1139                std::vector<gig::Region*> ignoredCritical;
1140                gig::Region* rgn = NULL;
1141                for (int key = 0; key < 128; ++key) {
1142                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1143                    rgn = instr->GetRegion(key);
1144    
1145                    // ignore all regions which do not exactly match the dimension
1146                    // layout of the selected region where this operation was emitted
1147                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1148                    if (!dimdef) {
1149                        ignoredAll.push_back(rgn);
1150                        ignoredMinor.push_back(rgn);
1151                        continue;
1152                    }
1153                    if (dimdef->zones != maindimdef.zones) {
1154                        ignoredAll.push_back(rgn);
1155                        ignoredCritical.push_back(rgn);
1156                        continue;
1157                    }
1158    
1159                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1160                }
1161                if (!ignoredAll.empty()) {
1162                    Glib::ustring txt;
1163                    if (ignoredCritical.empty())
1164                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1165                    else if (ignoredMinor.empty())
1166                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1167                    else
1168                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1169                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1170                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1171                    Gtk::MessageDialog msg(txt, false, type);
1172                    msg.run();
1173                }
1174            }
1175      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1176          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1177          msg.run();          msg.run();
# Line 907  void DimRegionChooser::split_dimension_z Line 1186  void DimRegionChooser::split_dimension_z
1186  void DimRegionChooser::delete_dimension_zone() {  void DimRegionChooser::delete_dimension_zone() {
1187      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1188      try {      try {
1189          region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);          if (!modifyallregions) {
1190                region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1191            } else {
1192                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1193                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1194                assert(pMaindimdef != NULL);
1195                // retain structure by value since the original region will be
1196                // modified in the loop below as well
1197                gig::dimension_def_t maindimdef = *pMaindimdef;
1198                std::vector<gig::Region*> ignoredAll;
1199                std::vector<gig::Region*> ignoredMinor;
1200                std::vector<gig::Region*> ignoredCritical;
1201                gig::Region* rgn = NULL;
1202                for (int key = 0; key < 128; ++key) {
1203                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1204                    rgn = instr->GetRegion(key);
1205    
1206                    // ignore all regions which do not exactly match the dimension
1207                    // layout of the selected region where this operation was emitted
1208                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1209                    if (!dimdef) {
1210                        ignoredAll.push_back(rgn);
1211                        ignoredMinor.push_back(rgn);
1212                        continue;
1213                    }
1214                    if (dimdef->zones != maindimdef.zones) {
1215                        ignoredAll.push_back(rgn);
1216                        ignoredCritical.push_back(rgn);
1217                        continue;
1218                    }
1219    
1220                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1221                }
1222                if (!ignoredAll.empty()) {
1223                    Glib::ustring txt;
1224                    if (ignoredCritical.empty())
1225                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1226                    else if (ignoredMinor.empty())
1227                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1228                    else
1229                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1230                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1231                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1232                    Gtk::MessageDialog msg(txt, false, type);
1233                    msg.run();
1234                }
1235            }
1236      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1237          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1238          msg.run();          msg.run();
# Line 919  void DimRegionChooser::delete_dimension_ Line 1244  void DimRegionChooser::delete_dimension_
1244      refresh_all();      refresh_all();
1245  }  }
1246    
1247    // Cmd key on Mac, Ctrl key on all other OSs
1248    static const guint primaryKeyL =
1249        #if defined(__APPLE__)
1250        GDK_KEY_Meta_L;
1251        #else
1252        GDK_KEY_Control_L;
1253        #endif
1254    
1255    static const guint primaryKeyR =
1256        #if defined(__APPLE__)
1257        GDK_KEY_Meta_R;
1258        #else
1259        GDK_KEY_Control_R;
1260        #endif
1261    
1262  bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {  bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1263      //printf("key down\n");      //printf("key down 0x%x\n", key->keyval);
1264      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1265          multiSelectKeyDown = true;          multiSelectKeyDown = true;
1266        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1267            primaryKeyDown = true;
1268        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1269            shiftKeyDown = true;
1270    
1271        //FIXME: hmm, for some reason GDKMM does not fire arrow key down events, so we are doing those handlers in the key up handler instead for now
1272        /*if (key->keyval == GDK_KEY_Left)
1273            select_prev_dimzone();
1274        if (key->keyval == GDK_KEY_Right)
1275            select_next_dimzone();
1276        if (key->keyval == GDK_KEY_Up)
1277            select_prev_dimension();
1278        if (key->keyval == GDK_KEY_Down)
1279            select_next_dimension();*/
1280      return false;      return false;
1281  }  }
1282    
1283  bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {  bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1284      //printf("key up\n");      //printf("key up 0x%x\n", key->keyval);
1285      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1286          multiSelectKeyDown = false;          multiSelectKeyDown = false;
1287        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1288            primaryKeyDown = false;
1289        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1290            shiftKeyDown = false;
1291    
1292        if (!has_focus()) return false;
1293    
1294        // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow
1295        // (which is supposed to switch between regions)
1296        if (primaryKeyDown) return false;
1297    
1298        // avoid conflict with Alt+Shift+Left and Alt+Shift+Right accelerators on
1299        // mainwindow
1300        if (shiftKeyDown) return false;
1301    
1302        if (key->keyval == GDK_KEY_Left)
1303            select_prev_dimzone();
1304        if (key->keyval == GDK_KEY_Right)
1305            select_next_dimzone();
1306        if (key->keyval == GDK_KEY_Up)
1307            select_prev_dimension();
1308        if (key->keyval == GDK_KEY_Down)
1309            select_next_dimension();
1310    
1311      return false;      return false;
1312  }  }
1313    
# Line 950  void DimRegionChooser::resetSelectedZone Line 1328  void DimRegionChooser::resetSelectedZone
1328      gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];      gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1329    
1330      bool isValidZone;      bool isValidZone;
1331      this->maindimcase = caseOfDimRegion(dimrgn, &isValidZone);      this->maindimcase = dimensionCaseOf(dimrgn);
     if (!isValidZone) {  
         queue_draw(); // redraw required parts  
         return;  
     }  
1332    
1333      for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();      for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1334           it != this->maindimcase.end(); ++it)           it != this->maindimcase.end(); ++it)
# Line 985  bool DimRegionChooser::select_dimregion( Line 1359  bool DimRegionChooser::select_dimregion(
1359      return false; //.selection failed      return false; //.selection failed
1360  }  }
1361    
1362    void DimRegionChooser::select_next_dimzone(bool add) {
1363        select_dimzone_by_dir(+1, add);
1364    }
1365    
1366    void DimRegionChooser::select_prev_dimzone(bool add) {
1367        select_dimzone_by_dir(-1, add);
1368    }
1369    
1370    void DimRegionChooser::select_dimzone_by_dir(int dir, bool add) {
1371        if (!region) return;
1372        if (!region->Dimensions) return;
1373        if (focus_line < 0) focus_line = 0;
1374        if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1375    
1376        maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1377        if (maindimtype == gig::dimension_none) {
1378            printf("maindimtype -> none\n");
1379            return;
1380        }
1381    
1382        if (maindimcase.empty()) {
1383            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1384            if (maindimcase.empty()) {
1385                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1386                return;
1387            }
1388        }
1389    
1390        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1391        if (z < 0) z = 0;
1392        if (z >= region->pDimensionDefinitions[focus_line].zones)
1393            z = region->pDimensionDefinitions[focus_line].zones - 1;
1394    
1395        maindimcase[maindimtype] = z;
1396    
1397        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1398        if (!dr) {
1399            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1400            return;
1401        }
1402    
1403        maindimregno = getDimensionRegionIndex(dr);
1404    
1405        if (!add) {
1406            // reset selected dimregion zones
1407            dimzones.clear();
1408        }
1409        for (DimensionCase::const_iterator it = maindimcase.begin();
1410             it != maindimcase.end(); ++it)
1411        {
1412            dimzones[it->first].insert(it->second);
1413        }
1414    
1415        dimregion_selected();
1416    
1417        // disabled: would overwrite dimregno with wrong value
1418        //refresh_all();
1419        // so requesting just a raw repaint instead:
1420        queue_draw();
1421    }
1422    
1423    void DimRegionChooser::select_next_dimension() {
1424        if (!region) return;
1425        focus_line++;
1426        if (focus_line >= region->Dimensions)
1427            focus_line = region->Dimensions - 1;
1428        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1429        queue_draw();
1430    }
1431    
1432    void DimRegionChooser::select_prev_dimension() {
1433        if (!region) return;
1434        focus_line--;
1435        if (focus_line < 0)
1436            focus_line = 0;
1437        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1438        queue_draw();
1439    }
1440    
1441  gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {  gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1442      if (!region) return NULL;      if (!region) return NULL;
1443      return region->pDimensionRegions[maindimregno];      return region->pDimensionRegions[maindimregno];

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

  ViewVC Help
Powered by ViewVC