/[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 2556 by schoenebeck, Fri May 16 23:19:23 2014 UTC revision 3147 by schoenebeck, Wed May 3 21:23:16 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2014 Andreas Persson   * Copyright (C) 2006-2017 Andreas Persson
3   *   *
4   * This program is free software; you can redistribute it and/or   * This program is free software; you can redistribute it and/or
5   * modify it under the terms of the GNU General Public License as   * modify it under the terms of the GNU General Public License as
# Line 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
20    #include <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  DimRegionChooser::DimRegionChooser() :  //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
35      red("#8070ff"),  static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
36        DimensionCase dimCase;
37        if (!dr) {
38            *isValidZone = false;
39            return dimCase;
40        }
41    
42        gig::Region* rgn = (gig::Region*) dr->GetParent();
43    
44        // find the dimension region index of the passed dimension region
45        int drIndex;
46        for (drIndex = 0; drIndex < 256; ++drIndex)
47            if (rgn->pDimensionRegions[drIndex] == dr)
48                break;
49    
50        // not found in region, something's horribly wrong
51        if (drIndex == 256) {
52            fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
53            *isValidZone = false;
54            return DimensionCase();
55        }
56    
57        for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
58            const int bits = rgn->pDimensionDefinitions[d].bits;
59            dimCase[rgn->pDimensionDefinitions[d].dimension] =
60                (drIndex >> baseBits) & ((1 << bits) - 1);
61            baseBits += bits;
62            // there are also DimensionRegion objects of unused zones, skip them
63            if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
64                *isValidZone = false;
65                return DimensionCase();
66            }
67        }
68    
69        *isValidZone = true;
70        return dimCase;
71    }
72    
73    DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
74        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      dimregno = -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 = 20;      h = 24;
150        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 74  DimRegionChooser::DimRegionChooser() : Line 192  DimRegionChooser::DimRegionChooser() :
192      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
193                 Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_HINT_MASK);
194    
     for (int i = 0 ; i < 256 ; i++) dimvalue[i] = 0;  
195      labels_changed = true;      labels_changed = true;
196    
197      set_tooltip_text(_("Right click here for options on altering dimension zones."));      set_tooltip_text(_(
198            "Right click here for options on altering dimension zones. Press and "
199            "hold CTRL key for selecting multiple dimension zones simultaniously."
200        ));
201        
202        window.signal_key_press_event().connect(
203            sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)
204        );
205        window.signal_key_release_event().connect(
206            sigc::mem_fun(*this, &DimRegionChooser::onKeyReleased)
207        );
208  }  }
209    
210  DimRegionChooser::~DimRegionChooser()  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 94  bool DimRegionChooser::on_expose_event(G Line 243  bool DimRegionChooser::on_expose_event(G
243    
244      const Cairo::RefPtr<Cairo::Context>& cr =      const Cairo::RefPtr<Cairo::Context>& cr =
245          get_window()->create_cairo_context();          get_window()->create_cairo_context();
 #if 0  
 }  
 #endif  
246  #else  #else
247  bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)  bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
248  {  {
# Line 175  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 212  bool DimRegionChooser::on_draw(const Cai Line 368  bool DimRegionChooser::on_draw(const Cai
368      for (int i = 0 ; i < region->Dimensions ; i++) {      for (int i = 0 ; i < region->Dimensions ; i++) {
369          int nbZones = region->pDimensionDefinitions[i].zones;          int nbZones = region->pDimensionDefinitions[i].zones;
370          if (nbZones) {          if (nbZones) {
371                const gig::dimension_t dimension = region->pDimensionDefinitions[i].dimension;
372    
373              if (y >= clipy2) break;              if (y >= clipy2) break;
374              if (y + h > clipy1) {              if (y + h > clipy1) {
375                  // draw focus rectangle around dimension's label and zones                  // draw focus rectangle around dimension's label and zones
376                  if (has_focus() && focus_line == i) {                  if (has_focus() && focus_line == i) {
377  #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
378                      Gdk::Rectangle farea(0, y, 150, 20);                      Gdk::Rectangle farea(0, y, 150, h);
379                      get_style()->paint_focus(get_window(), get_state(), farea,                      get_style()->paint_focus(get_window(), get_state(), farea,
380                                               *this, "",                                               *this, "",
381                                               0, y, label_width, 20);                                               0, y, label_width, h);
382  #else  #else
383                      get_style_context()->render_focus(cr,                      get_style_context()->render_focus(cr,
384                                                        0, y, label_width, 20);                                                        0, y, label_width, h);
385  #endif  #endif
386                  }                  }
387    
# Line 242  bool DimRegionChooser::on_draw(const Cai Line 400  bool DimRegionChooser::on_draw(const Cai
400                  cr->fill();                  cr->fill();
401    
402                  int c = 0;                  int c = 0;
403                  if (dimregno >= 0) {                  if (maindimregno >= 0) {
404                      int mask =                      int mask =
405                          ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<                          ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
406                            bitpos);                            bitpos);
407                      c = dimregno & mask; // mask away this dimension                      c = maindimregno & mask; // mask away this dimension
408                  }                  }
409                  bool customsplits =                  bool customsplits =
410                      ((region->pDimensionDefinitions[i].split_type ==                      ((region->pDimensionDefinitions[i].split_type ==
# Line 256  bool DimRegionChooser::on_draw(const Cai Line 414  bool DimRegionChooser::on_draw(const Cai
414                        gig::dimension_velocity &&                        gig::dimension_velocity &&
415                        region->pDimensionRegions[c]->VelocityUpperLimit));                        region->pDimensionRegions[c]->VelocityUpperLimit));
416    
417                  // draw dimension's zone borders                  // draw dimension zones
418                  Gdk::Cairo::set_source_rgba(cr, black);                  Gdk::Cairo::set_source_rgba(cr, black);
419                  if (customsplits) {                  if (customsplits) {
420                      cr->move_to(label_width + 0.5, y + 1);                      cr->move_to(label_width + 0.5, y + 1);
421                      cr->line_to(label_width + 0.5, y + h - 1);                      cr->line_to(label_width + 0.5, y + h - 1);
422                        int prevX = label_width;
423                        int prevUpperLimit = -1;
424    
425                      for (int j = 0 ; j < nbZones ; j++) {                      for (int j = 0 ; j < nbZones ; j++) {
426                            // draw dimension zone's borders for custom splits
427                          gig::DimensionRegion* d =                          gig::DimensionRegion* d =
428                              region->pDimensionRegions[c + (j << bitpos)];                              region->pDimensionRegions[c + (j << bitpos)];
429                          int upperLimit = d->DimensionUpperLimits[i];                          int upperLimit = d->DimensionUpperLimits[i];
# Line 272  bool DimRegionChooser::on_draw(const Cai Line 433  bool DimRegionChooser::on_draw(const Cai
433                              label_width;                              label_width;
434                          if (x >= clipx2) break;                          if (x >= clipx2) break;
435                          if (x < clipx1) continue;                          if (x < clipx1) continue;
436                            Gdk::Cairo::set_source_rgba(cr, black);
437                          cr->move_to(x + 0.5, y + 1);                          cr->move_to(x + 0.5, y + 1);
438                          cr->line_to(x + 0.5, y + h - 1);                          cr->line_to(x + 0.5, y + h - 1);
439                            cr->stroke();
440    
441                            // draw fill for zone
442                            bool isSelectedZone = this->dimzones[dimension].count(j);
443                            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);
460                            cr->fill();
461    
462                            // draw text showing the beginning of the dimension zone
463                            // as numeric value to the user
464                            {
465                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
466                                layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
467                                Gdk::Cairo::set_source_rgba(cr, black);
468                                // get the text dimensions
469                                int text_width, text_height;
470                                layout->get_pixel_size(text_width, text_height);
471                                // move text to the left end of the dimension zone
472                                cr->move_to(prevX + 3, y + (h - text_height) / 2);
473    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
474                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
475    #else
476                                layout->show_in_cairo_context(cr);
477    #endif
478                            }
479                            // draw text showing the end of the dimension zone
480                            // as numeric value to the user
481                            {
482                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
483                                layout->set_text(Glib::Ascii::dtostr(upperLimit));
484                                Gdk::Cairo::set_source_rgba(cr, black);
485                                // get the text dimensions
486                                int text_width, text_height;
487                                layout->get_pixel_size(text_width, text_height);
488                                // move text to the left end of the dimension zone
489                                cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
490    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
491                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
492    #else
493                                layout->show_in_cairo_context(cr);
494    #endif
495                            }
496    
497                            prevX = x;
498                            prevUpperLimit = upperLimit;
499                      }                      }
500                  } else {                  } else {
501                        int prevX = 0;
502                      for (int j = 0 ; j <= nbZones ; j++) {                      for (int j = 0 ; j <= nbZones ; j++) {
503                            // draw dimension zone's borders for normal splits
504                          int x = int((w - label_width - 1) * j /                          int x = int((w - label_width - 1) * j /
505                                      double(nbZones) + 0.5) + label_width;                                      double(nbZones) + 0.5) + label_width;
506                          if (x >= clipx2) break;                          if (x >= clipx2) break;
507                          if (x < clipx1) continue;                          if (x < clipx1) continue;
508                            Gdk::Cairo::set_source_rgba(cr, black);
509                          cr->move_to(x + 0.5, y + 1);                          cr->move_to(x + 0.5, y + 1);
510                          cr->line_to(x + 0.5, y + h - 1);                          cr->line_to(x + 0.5, y + h - 1);
511                      }                          cr->stroke();
                 }  
                 cr->stroke();  
512    
513                  // draw fill for currently selected zone                          if (j != 0) {
514                  if (dimregno >= 0) {                              // draw fill for zone
515                      Gdk::Cairo::set_source_rgba(cr, red);                              bool isSelectedZone = this->dimzones[dimension].count(j-1);
516                      int dr = (dimregno >> bitpos) &                              bool isMainSelection =
517                          ((1 << region->pDimensionDefinitions[i].bits) - 1);                                  this->maindimcase.find(dimension) != this->maindimcase.end() &&
518                                                        this->maindimcase[dimension] == (j-1);
519                      int x1 = -1, x2 = -1;                              bool isCheckBoxSelected =
520                      if (customsplits) {                                  modifyalldimregs ||
521                          x1 = label_width;                                  (modifybothchannels &&
522                          for (int j = 0 ; j < nbZones && x1 + 1 < clipx2 ; j++) {                                      dimension == gig::dimension_samplechannel);
523                              gig::DimensionRegion* d =                              if (isMainSelection)
524                                  region->pDimensionRegions[c + (j << bitpos)];                                  Gdk::Cairo::set_source_rgba(cr, blue);
525                              int upperLimit = d->DimensionUpperLimits[i];                              else if (isSelectedZone)
526                              if (!upperLimit) {                                  cr->set_source(blueHatchedSurfacePattern);
527                                  upperLimit = d->VelocityUpperLimit;                              else if (isCheckBoxSelected)
528                              }                                  cr->set_source(grayBlueHatchedSurfacePattern);
529                              int v = upperLimit + 1;                              else
530                              x2 = int((w - label_width - 1) * v / 128.0 +                                  Gdk::Cairo::set_source_rgba(cr, white);
531                                       0.5) + label_width;                              cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
                             if (j == dr && x1 < x2) {  
                                 cr->rectangle(x1 + 1, y + 1,  
                                               (x2 - x1) - 1, h - 2);  
                                 cr->fill();  
                                 break;  
                             }  
                             x1 = x2;  
                         }  
                     } else {  
                         if (dr < nbZones) {  
                             x1 = int((w - label_width - 1) * dr /  
                                      double(nbZones) + 0.5);  
                             x2 = int((w - label_width - 1) * (dr + 1) /  
                                      double(nbZones) + 0.5);  
                             cr->rectangle(label_width + x1 + 1, y + 1,  
                                           (x2 - x1) - 1, h - 2);  
532                              cr->fill();                              cr->fill();
                         }  
                     }  
533    
534                      // draw text showing the beginning of the dimension zone                              // draw text showing the beginning of the dimension zone
535                      // as numeric value to the user                              // as numeric value to the user
536                      if (x1 >= 0) {                              {
537                          Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
538                          int v = roundf(float(x1 - label_width) / float(w - label_width) * 127.f);                                  layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
539                          if (dr > 0) v++;                                  Gdk::Cairo::set_source_rgba(cr, black);
540                          layout->set_text(Glib::Ascii::dtostr(v));                                  // get the text dimensions
541                          Gdk::Cairo::set_source_rgba(cr, black);                                  int text_width, text_height;
542                          Pango::Rectangle rect = layout->get_logical_extents();                                  layout->get_pixel_size(text_width, text_height);
543                                                            // move text to the left end of the dimension zone
544                          int text_width, text_height;                                  cr->move_to(prevX + 3, y + (h - text_height) / 2);
                         // get the text dimensions  
                         layout->get_pixel_size(text_width, text_height);  
                         // move text to the right end of the dimension zone  
                         cr->move_to(x1 + 1, y + 1);  
545  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
546                          pango_cairo_show_layout(cr->cobj(), layout->gobj());                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());
547  #else  #else
548                          layout->show_in_cairo_context(cr);                                  layout->show_in_cairo_context(cr);
549  #endif  #endif
550                      }                              }
551                      // draw text showing the end of the dimension zone                              // draw text showing the end of the dimension zone
552                      // as numeric value to the user                              // as numeric value to the user
553                      if (x2 >= 0) {                              {
554                          Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
555                          const int v = roundf(float(x2 - label_width) / float(w - label_width) * 127.f);                                  layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
556                          layout->set_text(Glib::Ascii::dtostr(v));                                  Gdk::Cairo::set_source_rgba(cr, black);
557                          Gdk::Cairo::set_source_rgba(cr, black);                                  // get the text dimensions
558                          Pango::Rectangle rect = layout->get_logical_extents();                                  int text_width, text_height;
559                                                            layout->get_pixel_size(text_width, text_height);
560                          int text_width, text_height;                                  // move text to the left end of the dimension zone
561                          // get the text dimensions                                  cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
                         layout->get_pixel_size(text_width, text_height);  
                         // move text to the right end of the dimension zone  
                         cr->move_to(x2 - text_width - 1, y + 1);  
562  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
563                          pango_cairo_show_layout(cr->cobj(), layout->gobj());                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());
564  #else  #else
565                          layout->show_in_cairo_context(cr);                                  layout->show_in_cairo_context(cr);
566  #endif  #endif
567                      }                              }
568                            }
569                            prevX = x;
570                        }      
571                  }                  }
572              }              }
   
573              y += h;              y += h;
574          }          }
575          bitpos += region->pDimensionDefinitions[i].bits;          bitpos += region->pDimensionDefinitions[i].bits;
# Line 381  bool DimRegionChooser::on_draw(const Cai Line 581  bool DimRegionChooser::on_draw(const Cai
581  void DimRegionChooser::set_region(gig::Region* region)  void DimRegionChooser::set_region(gig::Region* region)
582  {  {
583      this->region = region;      this->region = region;
584      dimregno = 0;      maindimregno = 0;
585      nbDimensions = 0;      nbDimensions = 0;
586      if (region) {      if (region) {
587          int bitcount = 0;          int bitcount = 0;
# Line 389  void DimRegionChooser::set_region(gig::R Line 589  void DimRegionChooser::set_region(gig::R
589              if (region->pDimensionDefinitions[dim].bits == 0) continue;              if (region->pDimensionDefinitions[dim].bits == 0) continue;
590              nbDimensions++;              nbDimensions++;
591    
592              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
593                               region->pDimensionDefinitions[dim].zones - 1);                               region->pDimensionDefinitions[dim].zones - 1);
594              dimregno |= (z << bitcount);              maindimregno |= (z << bitcount);
595              bitcount += region->pDimensionDefinitions[dim].bits;              bitcount += region->pDimensionDefinitions[dim].bits;
596          }          }
         dimreg = region->pDimensionRegions[dimregno];  
     } else {  
         dimreg = 0;  
597      }      }
598      dimregion_selected();      dimregion_selected();
599      set_size_request(800, region ? nbDimensions * 20 : 0);      set_size_request(800, region ? nbDimensions * h : 0);
600    
601      labels_changed = true;      labels_changed = true;
602      queue_resize();      queue_resize();
603        queue_draw();
604  }  }
605    
606  void DimRegionChooser::refresh_all() {  void DimRegionChooser::refresh_all() {
# Line 412  void DimRegionChooser::refresh_all() { Line 610  void DimRegionChooser::refresh_all() {
610  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
611                                        std::set<gig::DimensionRegion*>& dimregs) const                                        std::set<gig::DimensionRegion*>& dimregs) const
612  {  {
613      int dimregno = 0;      for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
614      int bitcount = 0;          gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
615      int stereo_bit = 0;          if (!dimRgn) continue;
616      for (int dim = 0 ; dim < region->Dimensions ; dim++) {          bool isValidZone;
617          if (region->pDimensionDefinitions[dim].bits == 0) continue;          std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
618          if (stereo &&          if (!isValidZone) continue;
619              region->pDimensionDefinitions[dim].dimension == gig::dimension_samplechannel) {          for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
620              stereo_bit = (1 << bitcount);               it != dimCase.end(); ++it)
621          } else {          {
622              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
623                               region->pDimensionDefinitions[dim].zones - 1);  
624              dimregno |= (z << bitcount);              std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
625                    this->dimzones.find(it->first);
626                if (itSelectedDimension != this->dimzones.end() &&
627                    itSelectedDimension->second.count(it->second)) continue; // is selected
628    
629                goto notSelected;
630          }          }
631          bitcount += region->pDimensionDefinitions[dim].bits;  
632            dimregs.insert(dimRgn);
633    
634            notSelected:
635            ;
636      }      }
     dimregs.insert(region->pDimensionRegions[dimregno]);  
     if (stereo_bit) dimregs.insert(region->pDimensionRegions[dimregno | stereo_bit]);  
637  }  }
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 = dimregno & mask; // mask away this dimension          int c = maindimregno & mask; // mask away this dimension
661    
662          if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {          if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
663              // the velocity dimension didn't previously have              // the velocity dimension didn't previously have
# Line 464  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 487  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 503  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 568  bool DimRegionChooser::on_button_press_e Line 875  bool DimRegionChooser::on_button_press_e
875              }              }
876    
877              int i = dim;              int i = dim;
878              if (dimregno < 0) dimregno = 0;              if (maindimregno < 0) maindimregno = 0;
879              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
880              int c = dimregno & mask; // mask away this dimension              int c = this->maindimregno & mask; // mask away this dimension
881    
882              bool customsplits =              bool customsplits =
883                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
# Line 600  bool DimRegionChooser::on_button_press_e Line 907  bool DimRegionChooser::on_button_press_e
907                     region->pDimensionDefinitions[dim].split_type,                     region->pDimensionDefinitions[dim].split_type,
908                     region->pDimensionDefinitions[dim].zones,                     region->pDimensionDefinitions[dim].zones,
909                     region->pDimensionDefinitions[dim].zone_size);                     region->pDimensionDefinitions[dim].zone_size);
910              dimvalue[region->pDimensionDefinitions[dim].dimension] = z;              this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
911                this->maindimregno = c | (z << bitpos);
912              dimregno = c | (z << bitpos);              this->maindimtype = region->pDimensionDefinitions[dim].dimension;
913    
914              this->dimtype = dim;              if (multiSelectKeyDown) {
915              this->dimzone = z;                  if (dimzones[this->maindimtype].count(z)) {
916                        if (dimzones[this->maindimtype].size() > 1) {
917                            dimzones[this->maindimtype].erase(z);
918                        }
919                    } else {
920                        dimzones[this->maindimtype].insert(z);
921                    }
922                } else {
923                    this->dimzones.clear();
924                    for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
925                         it != this->maindimcase.end(); ++it)
926                    {
927                        this->dimzones[it->first].insert(it->second);
928                    }
929                }
930    
931              focus_line = dim;              focus_line = dim;
932              if (has_focus()) queue_draw();              if (has_focus()) queue_draw();
933              else grab_focus();              else grab_focus();
             dimreg = region->pDimensionRegions[dimregno];  
934              dimregion_selected();              dimregion_selected();
935    
936              if (event->button == 3) {              if (event->button == 3) {
937                  printf("dimregion right click\n");                  printf("dimregion right click\n");
938                  popup_menu_inside_dimregion->popup(event->button, event->time);                  popup_menu_inside_dimregion->popup(event->button, event->time);
939              }              }
940    
941                queue_draw();
942          }          }
943      }      }
944      return true;      return true;
# Line 654  bool DimRegionChooser::on_motion_notify_ Line 976  bool DimRegionChooser::on_motion_notify_
976    
977              resize.pos = k;              resize.pos = k;
978              update_after_resize();              update_after_resize();
979              get_window()->invalidate_rect(rect, false);              get_window()->invalidate_rect(rect, false); // not sufficient ...
980                queue_draw(); // ... so do a complete redraw instead.
981          }          }
982      } else {      } else {
983          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
# Line 690  bool DimRegionChooser::is_in_resize_zone Line 1013  bool DimRegionChooser::is_in_resize_zone
1013          int nbZones = region->pDimensionDefinitions[dim].zones;          int nbZones = region->pDimensionDefinitions[dim].zones;
1014    
1015          int c = 0;          int c = 0;
1016          if (dimregno >= 0) {          if (maindimregno >= 0) {
1017              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
1018              c = dimregno & mask; // mask away this dimension              c = maindimregno & mask; // mask away this dimension
1019          }          }
1020          const bool customsplits =          const bool customsplits =
1021              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
# Line 715  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    
1046                      int dr = (dimregno >> bitpos) &                      int dr = (maindimregno >> bitpos) &
1047                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);
1048                      resize.selected = dr == iZone ? resize.left :                      resize.selected = dr == iZone ? resize.left :
1049                          dr == iZone + 1 ? resize.right : resize.none;                          dr == iZone + 1 ? resize.right : resize.none;
# Line 756  sigc::signal<void>& DimRegionChooser::si Line 1080  sigc::signal<void>& DimRegionChooser::si
1080    
1081  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
1082  {  {
1083      // TODO: kolla att region finns osv, dvs att det går att sätta      // TODO: check that region exists etc, that is, that it's possible
1084      // fokus.      // to set focus
1085      if (direction == Gtk::DIR_TAB_FORWARD ||      if (direction == Gtk::DIR_TAB_FORWARD ||
1086          direction == Gtk::DIR_DOWN) {          direction == Gtk::DIR_DOWN) {
1087          if (!has_focus()) {          if (!has_focus()) {
# Line 789  bool DimRegionChooser::on_focus(Gtk::Dir Line 1113  bool DimRegionChooser::on_focus(Gtk::Dir
1113              }              }
1114          }          }
1115      } else if (!has_focus()) {      } else if (!has_focus()) {
1116          // TODO: kolla att focus_line finns!          // TODO: check that focus_line exists
1117          grab_focus();          grab_focus();
1118          return true;          return true;
1119      } else {      } else {
1120          // TODO: öka eller minska värde!          // TODO: increase or decrease value
1121      }      }
1122        return false;
1123  }  }
1124    
1125  void DimRegionChooser::split_dimension_zone() {  void DimRegionChooser::split_dimension_zone() {    
1126      printf("split_dimension_zone() type=%d, zone=%d\n", dimtype, dimzone);      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1127      try {      try {
1128          region->SplitDimensionZone(          if (!modifyallregions) {
1129              region->pDimensionDefinitions[dimtype].dimension,              region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1130              dimzone          } 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 816  void DimRegionChooser::split_dimension_z Line 1184  void DimRegionChooser::split_dimension_z
1184  }  }
1185    
1186  void DimRegionChooser::delete_dimension_zone() {  void DimRegionChooser::delete_dimension_zone() {
1187      printf("delete_dimension_zone() type=%d, zone=%d\n", dimtype, dimzone);      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1188      try {      try {
1189          region->DeleteDimensionZone(          if (!modifyallregions) {
1190              region->pDimensionDefinitions[dimtype].dimension,              region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1191              dimzone          } 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 832  void DimRegionChooser::delete_dimension_ Line 1243  void DimRegionChooser::delete_dimension_
1243      }      }
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) {
1263        //printf("key down 0x%x\n", key->keyval);
1264        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1265            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;
1281    }
1282    
1283    bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1284        //printf("key up 0x%x\n", key->keyval);
1285        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1286            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;
1312    }
1313    
1314    void DimRegionChooser::resetSelectedZones() {
1315        this->dimzones.clear();
1316        if (!region) {
1317            queue_draw(); // redraw required parts
1318            return;
1319        }
1320        if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1321            queue_draw(); // redraw required parts
1322            return;
1323        }
1324        if (!region->pDimensionRegions[maindimregno]) {
1325            queue_draw(); // redraw required parts
1326            return;
1327        }
1328        gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1329    
1330        bool isValidZone;
1331        this->maindimcase = dimensionCaseOf(dimrgn);
1332    
1333        for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1334             it != this->maindimcase.end(); ++it)
1335        {
1336            this->dimzones[it->first].insert(it->second);
1337        }
1338    
1339        // redraw required parts
1340        queue_draw();
1341    }
1342    
1343    bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1344        if (!region) return false; //.selection failed
1345    
1346        for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1347            if (region->pDimensionRegions[dr] == dimrgn) {
1348                // reset dim region zone selection to the requested specific dim region case
1349                maindimregno = dr;
1350                resetSelectedZones();
1351    
1352                // emit signal that dimregion selection has changed, for external entities
1353                dimregion_selected();
1354    
1355                return true; // selection success
1356            }
1357        }
1358    
1359        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 {
1442        if (!region) return NULL;
1443        return region->pDimensionRegions[maindimregno];
1444    }

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

  ViewVC Help
Powered by ViewVC