/[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 3158 by schoenebeck, Mon May 8 18:05:35 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>
27  #include <gtkmm/stock.h>  #include <gtkmm/stock.h>
28  #include <glibmm/ustring.h>  #include <glibmm/ustring.h>
29  #include <gtkmm/messagedialog.h>  #include <gtkmm/messagedialog.h>
30    #include <assert.h>
31    
32  #include "global.h"  #include "global.h"
33    #include "gfx/builtinpix.h"
34    
35  DimRegionChooser::DimRegionChooser() :  //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
36      red("#8070ff"),  static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
37        DimensionCase dimCase;
38        if (!dr) {
39            *isValidZone = false;
40            return dimCase;
41        }
42    
43        gig::Region* rgn = (gig::Region*) dr->GetParent();
44    
45        // find the dimension region index of the passed dimension region
46        int drIndex;
47        for (drIndex = 0; drIndex < 256; ++drIndex)
48            if (rgn->pDimensionRegions[drIndex] == dr)
49                break;
50    
51        // not found in region, something's horribly wrong
52        if (drIndex == 256) {
53            fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
54            *isValidZone = false;
55            return DimensionCase();
56        }
57    
58        for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
59            const int bits = rgn->pDimensionDefinitions[d].bits;
60            dimCase[rgn->pDimensionDefinitions[d].dimension] =
61                (drIndex >> baseBits) & ((1 << bits) - 1);
62            baseBits += bits;
63            // there are also DimensionRegion objects of unused zones, skip them
64            if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
65                *isValidZone = false;
66                return DimensionCase();
67            }
68        }
69    
70        *isValidZone = true;
71        return dimCase;
72    }
73    
74    DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
75        red("#ff476e"),
76        blue("#4796ff"),
77      black("black"),      black("black"),
78      white("white")      white("white")
79  {  {
80        // make sure blue hatched pattern pixmap is loaded
81        loadBuiltInPix();
82    
83        // create blue hatched pattern
84        {
85            const int width = blueHatchedPattern->get_width();
86            const int height = blueHatchedPattern->get_height();
87            const int stride = blueHatchedPattern->get_rowstride();
88    
89            // manually convert from RGBA to ARGB
90            this->blueHatchedPatternARGB = blueHatchedPattern->copy();
91            const int pixelSize = stride / width;
92            const int totalPixels = width * height;
93            assert(pixelSize == 4);
94            unsigned char* ptr = this->blueHatchedPatternARGB->get_pixels();
95            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
96                const unsigned char r = ptr[0];
97                const unsigned char g = ptr[1];
98                const unsigned char b = ptr[2];
99                const unsigned char a = ptr[3];
100                ptr[0] = b;
101                ptr[1] = g;
102                ptr[2] = r;
103                ptr[3] = a;
104            }
105    
106            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
107                this->blueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
108            );
109            this->blueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
110            this->blueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
111        }
112    
113        // create gray blue hatched pattern
114        {
115            const int width = grayBlueHatchedPattern->get_width();
116            const int height = grayBlueHatchedPattern->get_height();
117            const int stride = grayBlueHatchedPattern->get_rowstride();
118    
119            // manually convert from RGBA to ARGB
120            this->grayBlueHatchedPatternARGB = grayBlueHatchedPattern->copy();
121            const int pixelSize = stride / width;
122            const int totalPixels = width * height;
123            assert(pixelSize == 4);
124            unsigned char* ptr = this->grayBlueHatchedPatternARGB->get_pixels();
125            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
126                const unsigned char r = ptr[0];
127                const unsigned char g = ptr[1];
128                const unsigned char b = ptr[2];
129                const unsigned char a = ptr[3];
130                ptr[0] = b;
131                ptr[1] = g;
132                ptr[2] = r;
133                ptr[3] = a;
134            }
135    
136            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
137                this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
138            );
139            this->grayBlueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
140            this->grayBlueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
141        }
142    
143      instrument = 0;      instrument = 0;
144      region = 0;      region = 0;
145      dimregno = -1;      maindimregno = -1;
146        maindimtype = gig::dimension_none; // initialize with invalid dimension type
147      focus_line = 0;      focus_line = 0;
148      resize.active = false;      resize.active = false;
149      cursor_is_resize = false;      cursor_is_resize = false;
150      h = 20;      h = 24;
151        multiSelectKeyDown = false;
152        primaryKeyDown = false;
153        shiftKeyDown = false;
154        modifybothchannels = modifyalldimregs = modifybothchannels = false;
155      set_can_focus();      set_can_focus();
156    
157        const Glib::ustring txtUseCheckBoxAllRegions =
158            _("Use checkbox 'all regions' to control whether this should apply to all regions.");
159    
160      actionGroup = Gtk::ActionGroup::create();      actionGroup = Gtk::ActionGroup::create();
161        actionSplitDimZone = Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
162        actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
163      actionGroup->add(      actionGroup->add(
164          Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone")),          actionSplitDimZone,
165          sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)          sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
166      );      );
167        actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
168        actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
169      actionGroup->add(      actionGroup->add(
170          Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone")),          actionDeleteDimZone,
171          sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)          sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
172      );      );
173    
# Line 74  DimRegionChooser::DimRegionChooser() : Line 193  DimRegionChooser::DimRegionChooser() :
193      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
194                 Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_HINT_MASK);
195    
     for (int i = 0 ; i < 256 ; i++) dimvalue[i] = 0;  
196      labels_changed = true;      labels_changed = true;
197    
198      set_tooltip_text(_("Right click here for options on altering dimension zones."));      set_tooltip_text(_(
199            "Right click here for options on altering dimension zones. Press and "
200            "hold CTRL key for selecting multiple dimension zones simultaniously."
201        ));
202        
203        window.signal_key_press_event().connect(
204            sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)
205        );
206        window.signal_key_release_event().connect(
207            sigc::mem_fun(*this, &DimRegionChooser::onKeyReleased)
208        );
209  }  }
210    
211  DimRegionChooser::~DimRegionChooser()  DimRegionChooser::~DimRegionChooser()
212  {  {
213  }  }
214    
215    void DimRegionChooser::setModifyBothChannels(bool b) {
216        modifybothchannels = b;
217        // redraw required parts
218        queue_draw();
219    }
220    
221    void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
222        modifyalldimregs = b;
223        // redraw required parts
224        queue_draw();
225    }
226    
227    void DimRegionChooser::setModifyAllRegions(bool b) {
228        modifyallregions = b;
229    
230        actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
231        actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
232    
233        // redraw required parts
234        queue_draw();
235    }
236    
237  #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
238  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
239  {  {
# Line 94  bool DimRegionChooser::on_expose_event(G Line 244  bool DimRegionChooser::on_expose_event(G
244    
245      const Cairo::RefPtr<Cairo::Context>& cr =      const Cairo::RefPtr<Cairo::Context>& cr =
246          get_window()->create_cairo_context();          get_window()->create_cairo_context();
 #if 0  
 }  
 #endif  
247  #else  #else
248  bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)  bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
249  {  {
# Line 175  bool DimRegionChooser::on_draw(const Cai Line 322  bool DimRegionChooser::on_draw(const Cai
322                      dstr = dstrbuf;                      dstr = dstrbuf;
323                      break;                      break;
324                  }                  }
                 layout->set_text(dstr);  
325    
326                    // Since bold font yields in larger label width, we first always
327                    // set the bold text variant, retrieve its dimensions (as worst
328                    // case dimensions of the label) ...
329                    layout->set_markup("<b>" + Glib::ustring(dstr) + "</b>");
330                  Pango::Rectangle rectangle = layout->get_logical_extents();                  Pango::Rectangle rectangle = layout->get_logical_extents();
331                    // ... and then reset the label to regular font style in case
332                    // the line is not selected. Otherwise the right hand side
333                    // actual dimension zones would jump around on selection change.
334                    bool isSelectedLine = (focus_line == i);
335                    if (!isSelectedLine)
336                        layout->set_markup(dstr);
337    
338                  double text_w = double(rectangle.get_width()) / Pango::SCALE;                  double text_w = double(rectangle.get_width()) / Pango::SCALE;
339                  if (text_w > maxwidth) maxwidth = text_w;                  if (text_w > maxwidth) maxwidth = text_w;
340    
# Line 212  bool DimRegionChooser::on_draw(const Cai Line 369  bool DimRegionChooser::on_draw(const Cai
369      for (int i = 0 ; i < region->Dimensions ; i++) {      for (int i = 0 ; i < region->Dimensions ; i++) {
370          int nbZones = region->pDimensionDefinitions[i].zones;          int nbZones = region->pDimensionDefinitions[i].zones;
371          if (nbZones) {          if (nbZones) {
372                const gig::dimension_t dimension = region->pDimensionDefinitions[i].dimension;
373    
374              if (y >= clipy2) break;              if (y >= clipy2) break;
375              if (y + h > clipy1) {              if (y + h > clipy1) {
376                  // draw focus rectangle around dimension's label and zones                  // draw focus rectangle around dimension's label and zones
377                  if (has_focus() && focus_line == i) {                  if (has_focus() && focus_line == i) {
378  #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
379                      Gdk::Rectangle farea(0, y, 150, 20);                      Gdk::Rectangle farea(0, y, 150, h);
380                      get_style()->paint_focus(get_window(), get_state(), farea,                      get_style()->paint_focus(get_window(), get_state(), farea,
381                                               *this, "",                                               *this, "",
382                                               0, y, label_width, 20);                                               0, y, label_width, h);
383  #else  #else
384                      get_style_context()->render_focus(cr,                      get_style_context()->render_focus(cr,
385                                                        0, y, label_width, 20);                                                        0, y, label_width, h);
386  #endif  #endif
387                  }                  }
388    
# Line 242  bool DimRegionChooser::on_draw(const Cai Line 401  bool DimRegionChooser::on_draw(const Cai
401                  cr->fill();                  cr->fill();
402    
403                  int c = 0;                  int c = 0;
404                  if (dimregno >= 0) {                  if (maindimregno >= 0) {
405                      int mask =                      int mask =
406                          ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<                          ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
407                            bitpos);                            bitpos);
408                      c = dimregno & mask; // mask away this dimension                      c = maindimregno & mask; // mask away this dimension
409                  }                  }
410                  bool customsplits =                  bool customsplits =
411                      ((region->pDimensionDefinitions[i].split_type ==                      ((region->pDimensionDefinitions[i].split_type ==
# Line 256  bool DimRegionChooser::on_draw(const Cai Line 415  bool DimRegionChooser::on_draw(const Cai
415                        gig::dimension_velocity &&                        gig::dimension_velocity &&
416                        region->pDimensionRegions[c]->VelocityUpperLimit));                        region->pDimensionRegions[c]->VelocityUpperLimit));
417    
418                  // draw dimension's zone borders                  // draw dimension zones
419                  Gdk::Cairo::set_source_rgba(cr, black);                  Gdk::Cairo::set_source_rgba(cr, black);
420                  if (customsplits) {                  if (customsplits) {
421                      cr->move_to(label_width + 0.5, y + 1);                      cr->move_to(label_width + 0.5, y + 1);
422                      cr->line_to(label_width + 0.5, y + h - 1);                      cr->line_to(label_width + 0.5, y + h - 1);
423                        int prevX = label_width;
424                        int prevUpperLimit = -1;
425    
426                      for (int j = 0 ; j < nbZones ; j++) {                      for (int j = 0 ; j < nbZones ; j++) {
427                            // draw dimension zone's borders for custom splits
428                          gig::DimensionRegion* d =                          gig::DimensionRegion* d =
429                              region->pDimensionRegions[c + (j << bitpos)];                              region->pDimensionRegions[c + (j << bitpos)];
430                          int upperLimit = d->DimensionUpperLimits[i];                          int upperLimit = d->DimensionUpperLimits[i];
# Line 272  bool DimRegionChooser::on_draw(const Cai Line 434  bool DimRegionChooser::on_draw(const Cai
434                              label_width;                              label_width;
435                          if (x >= clipx2) break;                          if (x >= clipx2) break;
436                          if (x < clipx1) continue;                          if (x < clipx1) continue;
437                            Gdk::Cairo::set_source_rgba(cr, black);
438                          cr->move_to(x + 0.5, y + 1);                          cr->move_to(x + 0.5, y + 1);
439                          cr->line_to(x + 0.5, y + h - 1);                          cr->line_to(x + 0.5, y + h - 1);
440                            cr->stroke();
441    
442                            // draw fill for zone
443                            bool isSelectedZone = this->dimzones[dimension].count(j);
444                            bool isMainSelection =
445                                this->maindimcase.find(dimension) != this->maindimcase.end() &&
446                                this->maindimcase[dimension] == j;
447                            bool isCheckBoxSelected =
448                                modifyalldimregs ||
449                                (modifybothchannels &&
450                                    dimension == gig::dimension_samplechannel);
451                            if (isMainSelection)
452                                Gdk::Cairo::set_source_rgba(cr, blue);
453                            else if (isSelectedZone)
454                                cr->set_source(blueHatchedSurfacePattern);
455                            else if (isCheckBoxSelected)
456                                cr->set_source(grayBlueHatchedSurfacePattern);
457                            else
458                                Gdk::Cairo::set_source_rgba(cr, white);
459    
460                            cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
461                            cr->fill();
462    
463                            // draw text showing the beginning of the dimension zone
464                            // as numeric value to the user
465                            {
466                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
467                                layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
468                                Gdk::Cairo::set_source_rgba(cr, black);
469                                // get the text dimensions
470                                int text_width, text_height;
471                                layout->get_pixel_size(text_width, text_height);
472                                // move text to the left end of the dimension zone
473                                cr->move_to(prevX + 3, y + (h - text_height) / 2);
474    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
475                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
476    #else
477                                layout->show_in_cairo_context(cr);
478    #endif
479                            }
480                            // draw text showing the end of the dimension zone
481                            // as numeric value to the user
482                            {
483                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
484                                layout->set_text(Glib::Ascii::dtostr(upperLimit));
485                                Gdk::Cairo::set_source_rgba(cr, black);
486                                // get the text dimensions
487                                int text_width, text_height;
488                                layout->get_pixel_size(text_width, text_height);
489                                // move text to the left end of the dimension zone
490                                cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
491    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
492                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
493    #else
494                                layout->show_in_cairo_context(cr);
495    #endif
496                            }
497    
498                            prevX = x;
499                            prevUpperLimit = upperLimit;
500                      }                      }
501                  } else {                  } else {
502                        int prevX = 0;
503                      for (int j = 0 ; j <= nbZones ; j++) {                      for (int j = 0 ; j <= nbZones ; j++) {
504                            // draw dimension zone's borders for normal splits
505                          int x = int((w - label_width - 1) * j /                          int x = int((w - label_width - 1) * j /
506                                      double(nbZones) + 0.5) + label_width;                                      double(nbZones) + 0.5) + label_width;
507                          if (x >= clipx2) break;                          if (x >= clipx2) break;
508                          if (x < clipx1) continue;                          if (x < clipx1) continue;
509                            Gdk::Cairo::set_source_rgba(cr, black);
510                          cr->move_to(x + 0.5, y + 1);                          cr->move_to(x + 0.5, y + 1);
511                          cr->line_to(x + 0.5, y + h - 1);                          cr->line_to(x + 0.5, y + h - 1);
512                      }                          cr->stroke();
                 }  
                 cr->stroke();  
513    
514                  // draw fill for currently selected zone                          if (j != 0) {
515                  if (dimregno >= 0) {                              // draw fill for zone
516                      Gdk::Cairo::set_source_rgba(cr, red);                              bool isSelectedZone = this->dimzones[dimension].count(j-1);
517                      int dr = (dimregno >> bitpos) &                              bool isMainSelection =
518                          ((1 << region->pDimensionDefinitions[i].bits) - 1);                                  this->maindimcase.find(dimension) != this->maindimcase.end() &&
519                                                        this->maindimcase[dimension] == (j-1);
520                      int x1 = -1, x2 = -1;                              bool isCheckBoxSelected =
521                      if (customsplits) {                                  modifyalldimregs ||
522                          x1 = label_width;                                  (modifybothchannels &&
523                          for (int j = 0 ; j < nbZones && x1 + 1 < clipx2 ; j++) {                                      dimension == gig::dimension_samplechannel);
524                              gig::DimensionRegion* d =                              if (isMainSelection)
525                                  region->pDimensionRegions[c + (j << bitpos)];                                  Gdk::Cairo::set_source_rgba(cr, blue);
526                              int upperLimit = d->DimensionUpperLimits[i];                              else if (isSelectedZone)
527                              if (!upperLimit) {                                  cr->set_source(blueHatchedSurfacePattern);
528                                  upperLimit = d->VelocityUpperLimit;                              else if (isCheckBoxSelected)
529                              }                                  cr->set_source(grayBlueHatchedSurfacePattern);
530                              int v = upperLimit + 1;                              else
531                              x2 = int((w - label_width - 1) * v / 128.0 +                                  Gdk::Cairo::set_source_rgba(cr, white);
532                                       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);  
533                              cr->fill();                              cr->fill();
                         }  
                     }  
534    
535                      // draw text showing the beginning of the dimension zone                              // draw text showing the beginning of the dimension zone
536                      // as numeric value to the user                              // as numeric value to the user
537                      if (x1 >= 0) {                              {
538                          Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
539                          int v = roundf(float(x1 - label_width) / float(w - label_width) * 127.f);                                  layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
540                          if (dr > 0) v++;                                  Gdk::Cairo::set_source_rgba(cr, black);
541                          layout->set_text(Glib::Ascii::dtostr(v));                                  // get the text dimensions
542                          Gdk::Cairo::set_source_rgba(cr, black);                                  int text_width, text_height;
543                          Pango::Rectangle rect = layout->get_logical_extents();                                  layout->get_pixel_size(text_width, text_height);
544                                                            // move text to the left end of the dimension zone
545                          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);  
546  #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
547                          pango_cairo_show_layout(cr->cobj(), layout->gobj());                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());
548  #else  #else
549                          layout->show_in_cairo_context(cr);                                  layout->show_in_cairo_context(cr);
550  #endif  #endif
551                      }                              }
552                      // draw text showing the end of the dimension zone                              // draw text showing the end of the dimension zone
553                      // as numeric value to the user                              // as numeric value to the user
554                      if (x2 >= 0) {                              {
555                          Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
556                          const int v = roundf(float(x2 - label_width) / float(w - label_width) * 127.f);                                  layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
557                          layout->set_text(Glib::Ascii::dtostr(v));                                  Gdk::Cairo::set_source_rgba(cr, black);
558                          Gdk::Cairo::set_source_rgba(cr, black);                                  // get the text dimensions
559                          Pango::Rectangle rect = layout->get_logical_extents();                                  int text_width, text_height;
560                                                            layout->get_pixel_size(text_width, text_height);
561                          int text_width, text_height;                                  // move text to the left end of the dimension zone
562                          // 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);  
563  #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
564                          pango_cairo_show_layout(cr->cobj(), layout->gobj());                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());
565  #else  #else
566                          layout->show_in_cairo_context(cr);                                  layout->show_in_cairo_context(cr);
567  #endif  #endif
568                      }                              }
569                            }
570                            prevX = x;
571                        }      
572                  }                  }
573              }              }
   
574              y += h;              y += h;
575          }          }
576          bitpos += region->pDimensionDefinitions[i].bits;          bitpos += region->pDimensionDefinitions[i].bits;
# Line 381  bool DimRegionChooser::on_draw(const Cai Line 582  bool DimRegionChooser::on_draw(const Cai
582  void DimRegionChooser::set_region(gig::Region* region)  void DimRegionChooser::set_region(gig::Region* region)
583  {  {
584      this->region = region;      this->region = region;
585      dimregno = 0;      maindimregno = 0;
586      nbDimensions = 0;      nbDimensions = 0;
587      if (region) {      if (region) {
588          int bitcount = 0;          int bitcount = 0;
# Line 389  void DimRegionChooser::set_region(gig::R Line 590  void DimRegionChooser::set_region(gig::R
590              if (region->pDimensionDefinitions[dim].bits == 0) continue;              if (region->pDimensionDefinitions[dim].bits == 0) continue;
591              nbDimensions++;              nbDimensions++;
592    
593              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
594                               region->pDimensionDefinitions[dim].zones - 1);                               region->pDimensionDefinitions[dim].zones - 1);
595              dimregno |= (z << bitcount);              maindimregno |= (z << bitcount);
596              bitcount += region->pDimensionDefinitions[dim].bits;              bitcount += region->pDimensionDefinitions[dim].bits;
597          }          }
         dimreg = region->pDimensionRegions[dimregno];  
     } else {  
         dimreg = 0;  
598      }      }
599      dimregion_selected();      dimregion_selected();
600      set_size_request(800, region ? nbDimensions * 20 : 0);      set_size_request(800, region ? nbDimensions * h : 0);
601    
602      labels_changed = true;      labels_changed = true;
603      queue_resize();      queue_resize();
604        queue_draw();
605  }  }
606    
607  void DimRegionChooser::refresh_all() {  void DimRegionChooser::refresh_all() {
# Line 412  void DimRegionChooser::refresh_all() { Line 611  void DimRegionChooser::refresh_all() {
611  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
612                                        std::set<gig::DimensionRegion*>& dimregs) const                                        std::set<gig::DimensionRegion*>& dimregs) const
613  {  {
614      int dimregno = 0;      for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
615      int bitcount = 0;          gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
616      int stereo_bit = 0;          if (!dimRgn) continue;
617      for (int dim = 0 ; dim < region->Dimensions ; dim++) {          bool isValidZone;
618          if (region->pDimensionDefinitions[dim].bits == 0) continue;          std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
619          if (stereo &&          if (!isValidZone) continue;
620              region->pDimensionDefinitions[dim].dimension == gig::dimension_samplechannel) {          for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
621              stereo_bit = (1 << bitcount);               it != dimCase.end(); ++it)
622          } else {          {
623              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
624                               region->pDimensionDefinitions[dim].zones - 1);  
625              dimregno |= (z << bitcount);              std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
626                    this->dimzones.find(it->first);
627                if (itSelectedDimension != this->dimzones.end() &&
628                    itSelectedDimension->second.count(it->second)) continue; // is selected
629    
630                goto notSelected;
631          }          }
632          bitcount += region->pDimensionDefinitions[dim].bits;  
633            dimregs.insert(dimRgn);
634    
635            notSelected:
636            ;
637      }      }
     dimregs.insert(region->pDimensionRegions[dimregno]);  
     if (stereo_bit) dimregs.insert(region->pDimensionRegions[dimregno | stereo_bit]);  
638  }  }
639    
640  void DimRegionChooser::update_after_resize()  void DimRegionChooser::update_after_resize()
641  {  {
642      if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {      const uint8_t upperLimit = resize.pos - 1;
643        gig::Instrument* instr = (gig::Instrument*)region->GetParent();
644    
645          int bitpos = 0;      int bitpos = 0;
646          for (int j = 0 ; j < resize.dimension ; j++) {      for (int j = 0 ; j < resize.dimension ; j++) {
647              bitpos += region->pDimensionDefinitions[j].bits;          bitpos += region->pDimensionDefinitions[j].bits;
648          }      }
649    
650        const int stereobitpos =
651            (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
652    
653        // the velocity dimension must be handled differently than all other
654        // dimension types, because
655        // 1. it is currently the only dimension type which allows different zone
656        //    sizes for different cases
657        // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
658        if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
659          int mask =          int mask =
660              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
661          int c = dimregno & mask; // mask away this dimension          int c = maindimregno & mask; // mask away this dimension
662    
663          if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {          if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
664              // the velocity dimension didn't previously have              // the velocity dimension didn't previously have
# Line 464  void DimRegionChooser::update_after_resi Line 681  void DimRegionChooser::update_after_resi
681              }              }
682          }          }
683    
684          gig::DimensionRegion* d = region->pDimensionRegions[c + resize.offset];          int index = c + (resize.zone << bitpos);
685            gig::DimensionRegion* d = region->pDimensionRegions[index];
686          // update both v2 and v3 values          // update both v2 and v3 values
687          d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;          d->DimensionUpperLimits[resize.dimension] = upperLimit;
688          d->VelocityUpperLimit = resize.pos - 1;          d->VelocityUpperLimit = upperLimit;
689            if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
690                gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
691                d->DimensionUpperLimits[resize.dimension] = upperLimit;
692                d->VelocityUpperLimit = upperLimit;
693            }
694    
695            if (modifyalldimregs) {
696                gig::Region* rgn = NULL;
697                for (int key = 0; key < 128; ++key) {
698                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
699                    rgn = instr->GetRegion(key);
700                    if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
701                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
702                    if (!dimdef) continue;
703                    if (dimdef->zones != resize.dimensionDef.zones) continue;
704                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
705                    assert(iDim >= 0 && iDim < rgn->Dimensions);
706    
707                    // the dimension layout might be completely different in this
708                    // region, so we have to recalculate bitpos etc for this region
709                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
710                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
711                    const int selection = resize.zone << bitpos;
712    
713                    // primitive and inefficient loop implementation, however due to
714                    // this circumstance the loop code is much simpler, and its lack
715                    // of runtime efficiency should not be notable in practice
716                    for (int idr = 0; idr < 256; ++idr) {
717                        const int index = (idr & stencil) | selection;
718                        assert(index >= 0 && index < 256);
719                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
720                        if (!dr) continue;
721                        dr->DimensionUpperLimits[iDim] = upperLimit;
722                        d->VelocityUpperLimit = upperLimit;
723                    }
724                }
725            } else if (modifyallregions) { // implies modifyalldimregs is false ...
726                // resolve the precise case we need to modify for all other regions
727                DimensionCase dimCase = dimensionCaseOf(d);
728                // apply the velocity upper limit change to that resolved dim case
729                // of all regions ...
730                gig::Region* rgn = NULL;
731                for (int key = 0; key < 128; ++key) {
732                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
733                    rgn = instr->GetRegion(key);
734                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
735                    if (!dimdef) continue;
736                    if (dimdef->zones != resize.dimensionDef.zones) continue;
737                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
738                    assert(iDim >= 0 && iDim < rgn->Dimensions);
739    
740                    std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
741                    for (int i = 0; i < dimrgns.size(); ++i) {
742                        gig::DimensionRegion* dr = dimrgns[i];
743                        dr->DimensionUpperLimits[iDim] = upperLimit;
744                        dr->VelocityUpperLimit = upperLimit;
745                    }
746                }
747            }
748      } else {      } else {
749          for (int i = 0 ; i < region->DimensionRegions ; ) {          for (int i = 0 ; i < region->DimensionRegions ; ) {
   
750              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
751                  // the dimension didn't previously have custom                  // the dimension didn't previously have custom
752                  // limits, so we have to set default limits for                  // limits, so we have to set default limits for
753                  // all the dimension regions                  // all the dimension regions
                 int bitpos = 0;  
                 for (int j = 0 ; j < resize.dimension ; j++) {  
                     bitpos += region->pDimensionDefinitions[j].bits;  
                 }  
754                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
755    
756                  for (int j = 0 ; j < nbZones ; j++) {                  for (int j = 0 ; j < nbZones ; j++) {
# Line 487  void DimRegionChooser::update_after_resi Line 758  void DimRegionChooser::update_after_resi
758                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
759                  }                  }
760              }              }
761              gig::DimensionRegion* d = region->pDimensionRegions[i + resize.offset];              int index = i + (resize.zone << bitpos);
762              d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              gig::DimensionRegion* d = region->pDimensionRegions[index];
763                d->DimensionUpperLimits[resize.dimension] = upperLimit;
764    #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
765                if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
766                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
767                    d->DimensionUpperLimits[resize.dimension] = upperLimit;
768                }
769    #endif
770              int bitpos = 0;              int bitpos = 0;
771              int j;              int j;
772              for (j = 0 ; j < region->Dimensions ; j++) {              for (j = 0 ; j < region->Dimensions ; j++) {
# Line 503  void DimRegionChooser::update_after_resi Line 780  void DimRegionChooser::update_after_resi
780              if (j == region->Dimensions) break;              if (j == region->Dimensions) break;
781              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
782          }          }
783    
784            if (modifyallregions) { // TODO: this code block could be merged with the similar (and more generalized) code block of the velocity dimension above
785                gig::Region* rgn = NULL;
786                for (int key = 0; key < 128; ++key) {
787                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
788                    rgn = instr->GetRegion(key);
789                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
790                    if (!dimdef) continue;
791                    if (dimdef->zones != resize.dimensionDef.zones) continue;
792                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
793                    assert(iDim >= 0 && iDim < rgn->Dimensions);
794    
795                    // the dimension layout might be completely different in this
796                    // region, so we have to recalculate bitpos etc for this region
797                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
798                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
799                    const int selection = resize.zone << bitpos;
800    
801                    // this loop implementation is less efficient than the above's
802                    // loop implementation (which skips unnecessary dimension regions)
803                    // however this code is much simpler, and its lack of runtime
804                    // efficiency should not be notable in practice
805                    for (int idr = 0; idr < 256; ++idr) {
806                        const int index = (idr & stencil) | selection;
807                        assert(index >= 0 && index < 256);
808                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
809                        if (!dr) continue;
810                        dr->DimensionUpperLimits[iDim] = upperLimit;
811                    }
812                }
813            }
814      }      }
815  }  }
816    
# Line 568  bool DimRegionChooser::on_button_press_e Line 876  bool DimRegionChooser::on_button_press_e
876              }              }
877    
878              int i = dim;              int i = dim;
879              if (dimregno < 0) dimregno = 0;              if (maindimregno < 0) maindimregno = 0;
880              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
881              int c = dimregno & mask; // mask away this dimension              int c = this->maindimregno & mask; // mask away this dimension
882    
883              bool customsplits =              bool customsplits =
884                  ((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 908  bool DimRegionChooser::on_button_press_e
908                     region->pDimensionDefinitions[dim].split_type,                     region->pDimensionDefinitions[dim].split_type,
909                     region->pDimensionDefinitions[dim].zones,                     region->pDimensionDefinitions[dim].zones,
910                     region->pDimensionDefinitions[dim].zone_size);                     region->pDimensionDefinitions[dim].zone_size);
911              dimvalue[region->pDimensionDefinitions[dim].dimension] = z;              this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
912                this->maindimregno = c | (z << bitpos);
913              dimregno = c | (z << bitpos);              this->maindimtype = region->pDimensionDefinitions[dim].dimension;
914    
915              this->dimtype = dim;              if (multiSelectKeyDown) {
916              this->dimzone = z;                  if (dimzones[this->maindimtype].count(z)) {
917                        if (dimzones[this->maindimtype].size() > 1) {
918                            dimzones[this->maindimtype].erase(z);
919                        }
920                    } else {
921                        dimzones[this->maindimtype].insert(z);
922                    }
923                } else {
924                    this->dimzones.clear();
925                    for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
926                         it != this->maindimcase.end(); ++it)
927                    {
928                        this->dimzones[it->first].insert(it->second);
929                    }
930                }
931    
932              focus_line = dim;              focus_line = dim;
933              if (has_focus()) queue_draw();              if (has_focus()) queue_draw();
934              else grab_focus();              else grab_focus();
             dimreg = region->pDimensionRegions[dimregno];  
935              dimregion_selected();              dimregion_selected();
936    
937              if (event->button == 3) {              if (event->button == 3) {
938                  printf("dimregion right click\n");                  printf("dimregion right click\n");
939                  popup_menu_inside_dimregion->popup(event->button, event->time);                  popup_menu_inside_dimregion->popup(event->button, event->time);
940              }              }
941    
942                queue_draw();
943          }          }
944      }      }
945      return true;      return true;
# Line 654  bool DimRegionChooser::on_motion_notify_ Line 977  bool DimRegionChooser::on_motion_notify_
977    
978              resize.pos = k;              resize.pos = k;
979              update_after_resize();              update_after_resize();
980              get_window()->invalidate_rect(rect, false);              get_window()->invalidate_rect(rect, false); // not sufficient ...
981                queue_draw(); // ... so do a complete redraw instead.
982          }          }
983      } else {      } else {
984          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
# Line 690  bool DimRegionChooser::is_in_resize_zone Line 1014  bool DimRegionChooser::is_in_resize_zone
1014          int nbZones = region->pDimensionDefinitions[dim].zones;          int nbZones = region->pDimensionDefinitions[dim].zones;
1015    
1016          int c = 0;          int c = 0;
1017          if (dimregno >= 0) {          if (maindimregno >= 0) {
1018              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
1019              c = dimregno & mask; // mask away this dimension              c = maindimregno & mask; // mask away this dimension
1020          }          }
1021          const bool customsplits =          const bool customsplits =
1022              ((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 1039  bool DimRegionChooser::is_in_resize_zone
1039                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
1040                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
1041                      resize.dimension = dim;                      resize.dimension = dim;
1042                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
1043                        resize.zone = iZone;
1044                      resize.pos = limit;                      resize.pos = limit;
1045                      resize.min = prev_limit;                      resize.min = prev_limit;
1046    
1047                      int dr = (dimregno >> bitpos) &                      int dr = (maindimregno >> bitpos) &
1048                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);
1049                      resize.selected = dr == iZone ? resize.left :                      resize.selected = dr == iZone ? resize.left :
1050                          dr == iZone + 1 ? resize.right : resize.none;                          dr == iZone + 1 ? resize.right : resize.none;
# Line 756  sigc::signal<void>& DimRegionChooser::si Line 1081  sigc::signal<void>& DimRegionChooser::si
1081    
1082  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
1083  {  {
1084      // 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
1085      // fokus.      // to set focus
1086      if (direction == Gtk::DIR_TAB_FORWARD ||      if (direction == Gtk::DIR_TAB_FORWARD ||
1087          direction == Gtk::DIR_DOWN) {          direction == Gtk::DIR_DOWN) {
1088          if (!has_focus()) {          if (!has_focus()) {
# Line 789  bool DimRegionChooser::on_focus(Gtk::Dir Line 1114  bool DimRegionChooser::on_focus(Gtk::Dir
1114              }              }
1115          }          }
1116      } else if (!has_focus()) {      } else if (!has_focus()) {
1117          // TODO: kolla att focus_line finns!          // TODO: check that focus_line exists
1118          grab_focus();          grab_focus();
1119          return true;          return true;
1120      } else {      } else {
1121          // TODO: öka eller minska värde!          // TODO: increase or decrease value
1122      }      }
1123        return false;
1124  }  }
1125    
1126  void DimRegionChooser::split_dimension_zone() {  void DimRegionChooser::split_dimension_zone() {    
1127      printf("split_dimension_zone() type=%d, zone=%d\n", dimtype, dimzone);      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1128      try {      try {
1129          region->SplitDimensionZone(          if (!modifyallregions) {
1130              region->pDimensionDefinitions[dimtype].dimension,              region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1131              dimzone          } else {
1132          );              gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1133                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1134                assert(pMaindimdef != NULL);
1135                // retain structure by value since the original region will be
1136                // modified in the loop below as well
1137                gig::dimension_def_t maindimdef = *pMaindimdef;
1138                std::vector<gig::Region*> ignoredAll;
1139                std::vector<gig::Region*> ignoredMinor;
1140                std::vector<gig::Region*> ignoredCritical;
1141                gig::Region* rgn = NULL;
1142                for (int key = 0; key < 128; ++key) {
1143                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1144                    rgn = instr->GetRegion(key);
1145    
1146                    // ignore all regions which do not exactly match the dimension
1147                    // layout of the selected region where this operation was emitted
1148                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1149                    if (!dimdef) {
1150                        ignoredAll.push_back(rgn);
1151                        ignoredMinor.push_back(rgn);
1152                        continue;
1153                    }
1154                    if (dimdef->zones != maindimdef.zones) {
1155                        ignoredAll.push_back(rgn);
1156                        ignoredCritical.push_back(rgn);
1157                        continue;
1158                    }
1159    
1160                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1161                }
1162                if (!ignoredAll.empty()) {
1163                    Glib::ustring txt;
1164                    if (ignoredCritical.empty())
1165                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1166                    else if (ignoredMinor.empty())
1167                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1168                    else
1169                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1170                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1171                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1172                    Gtk::MessageDialog msg(txt, false, type);
1173                    msg.run();
1174                }
1175            }
1176      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1177          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1178          msg.run();          msg.run();
# Line 816  void DimRegionChooser::split_dimension_z Line 1185  void DimRegionChooser::split_dimension_z
1185  }  }
1186    
1187  void DimRegionChooser::delete_dimension_zone() {  void DimRegionChooser::delete_dimension_zone() {
1188      printf("delete_dimension_zone() type=%d, zone=%d\n", dimtype, dimzone);      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1189      try {      try {
1190          region->DeleteDimensionZone(          if (!modifyallregions) {
1191              region->pDimensionDefinitions[dimtype].dimension,              region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1192              dimzone          } else {
1193          );              gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1194                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1195                assert(pMaindimdef != NULL);
1196                // retain structure by value since the original region will be
1197                // modified in the loop below as well
1198                gig::dimension_def_t maindimdef = *pMaindimdef;
1199                std::vector<gig::Region*> ignoredAll;
1200                std::vector<gig::Region*> ignoredMinor;
1201                std::vector<gig::Region*> ignoredCritical;
1202                gig::Region* rgn = NULL;
1203                for (int key = 0; key < 128; ++key) {
1204                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1205                    rgn = instr->GetRegion(key);
1206    
1207                    // ignore all regions which do not exactly match the dimension
1208                    // layout of the selected region where this operation was emitted
1209                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1210                    if (!dimdef) {
1211                        ignoredAll.push_back(rgn);
1212                        ignoredMinor.push_back(rgn);
1213                        continue;
1214                    }
1215                    if (dimdef->zones != maindimdef.zones) {
1216                        ignoredAll.push_back(rgn);
1217                        ignoredCritical.push_back(rgn);
1218                        continue;
1219                    }
1220    
1221                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1222                }
1223                if (!ignoredAll.empty()) {
1224                    Glib::ustring txt;
1225                    if (ignoredCritical.empty())
1226                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1227                    else if (ignoredMinor.empty())
1228                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1229                    else
1230                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1231                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1232                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1233                    Gtk::MessageDialog msg(txt, false, type);
1234                    msg.run();
1235                }
1236            }
1237      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1238          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1239          msg.run();          msg.run();
# Line 832  void DimRegionChooser::delete_dimension_ Line 1244  void DimRegionChooser::delete_dimension_
1244      }      }
1245      refresh_all();      refresh_all();
1246  }  }
1247    
1248    // Cmd key on Mac, Ctrl key on all other OSs
1249    static const guint primaryKeyL =
1250        #if defined(__APPLE__)
1251        GDK_KEY_Meta_L;
1252        #else
1253        GDK_KEY_Control_L;
1254        #endif
1255    
1256    static const guint primaryKeyR =
1257        #if defined(__APPLE__)
1258        GDK_KEY_Meta_R;
1259        #else
1260        GDK_KEY_Control_R;
1261        #endif
1262    
1263    bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1264        //printf("key down 0x%x\n", key->keyval);
1265        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1266            multiSelectKeyDown = true;
1267        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1268            primaryKeyDown = true;
1269        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1270            shiftKeyDown = true;
1271    
1272        //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
1273        /*if (key->keyval == GDK_KEY_Left)
1274            select_prev_dimzone();
1275        if (key->keyval == GDK_KEY_Right)
1276            select_next_dimzone();
1277        if (key->keyval == GDK_KEY_Up)
1278            select_prev_dimension();
1279        if (key->keyval == GDK_KEY_Down)
1280            select_next_dimension();*/
1281        return false;
1282    }
1283    
1284    bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1285        //printf("key up 0x%x\n", key->keyval);
1286        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1287            multiSelectKeyDown = false;
1288        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1289            primaryKeyDown = false;
1290        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1291            shiftKeyDown = false;
1292    
1293        if (!has_focus()) return false;
1294    
1295        // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow
1296        // (which is supposed to switch between regions)
1297        if (primaryKeyDown) return false;
1298    
1299        // avoid conflict with Alt+Shift+Left and Alt+Shift+Right accelerators on
1300        // mainwindow
1301        if (shiftKeyDown) return false;
1302    
1303        if (key->keyval == GDK_KEY_Left)
1304            select_prev_dimzone();
1305        if (key->keyval == GDK_KEY_Right)
1306            select_next_dimzone();
1307        if (key->keyval == GDK_KEY_Up)
1308            select_prev_dimension();
1309        if (key->keyval == GDK_KEY_Down)
1310            select_next_dimension();
1311    
1312        return false;
1313    }
1314    
1315    void DimRegionChooser::resetSelectedZones() {
1316        this->dimzones.clear();
1317        if (!region) {
1318            queue_draw(); // redraw required parts
1319            return;
1320        }
1321        if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1322            queue_draw(); // redraw required parts
1323            return;
1324        }
1325        if (!region->pDimensionRegions[maindimregno]) {
1326            queue_draw(); // redraw required parts
1327            return;
1328        }
1329        gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1330    
1331        bool isValidZone;
1332        this->maindimcase = dimensionCaseOf(dimrgn);
1333    
1334        for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1335             it != this->maindimcase.end(); ++it)
1336        {
1337            this->dimzones[it->first].insert(it->second);
1338        }
1339    
1340        // redraw required parts
1341        queue_draw();
1342    }
1343    
1344    bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1345        if (!region) return false; //.selection failed
1346    
1347        for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1348            if (region->pDimensionRegions[dr] == dimrgn) {
1349                // reset dim region zone selection to the requested specific dim region case
1350                maindimregno = dr;
1351                resetSelectedZones();
1352    
1353                // emit signal that dimregion selection has changed, for external entities
1354                dimregion_selected();
1355    
1356                return true; // selection success
1357            }
1358        }
1359    
1360        return false; //.selection failed
1361    }
1362    
1363    void DimRegionChooser::select_next_dimzone(bool add) {
1364        select_dimzone_by_dir(+1, add);
1365    }
1366    
1367    void DimRegionChooser::select_prev_dimzone(bool add) {
1368        select_dimzone_by_dir(-1, add);
1369    }
1370    
1371    void DimRegionChooser::select_dimzone_by_dir(int dir, bool add) {
1372        if (!region) return;
1373        if (!region->Dimensions) return;
1374        if (focus_line < 0) focus_line = 0;
1375        if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1376    
1377        maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1378        if (maindimtype == gig::dimension_none) {
1379            printf("maindimtype -> none\n");
1380            return;
1381        }
1382    
1383        if (maindimcase.empty()) {
1384            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1385            if (maindimcase.empty()) {
1386                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1387                return;
1388            }
1389        }
1390    
1391        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1392        if (z < 0) z = 0;
1393        if (z >= region->pDimensionDefinitions[focus_line].zones)
1394            z = region->pDimensionDefinitions[focus_line].zones - 1;
1395    
1396        maindimcase[maindimtype] = z;
1397    
1398        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1399        if (!dr) {
1400            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1401            return;
1402        }
1403    
1404        maindimregno = getDimensionRegionIndex(dr);
1405    
1406        if (!add) {
1407            // reset selected dimregion zones
1408            dimzones.clear();
1409        }
1410        for (DimensionCase::const_iterator it = maindimcase.begin();
1411             it != maindimcase.end(); ++it)
1412        {
1413            dimzones[it->first].insert(it->second);
1414        }
1415    
1416        dimregion_selected();
1417    
1418        // disabled: would overwrite dimregno with wrong value
1419        //refresh_all();
1420        // so requesting just a raw repaint instead:
1421        queue_draw();
1422    }
1423    
1424    void DimRegionChooser::select_next_dimension() {
1425        if (!region) return;
1426        focus_line++;
1427        if (focus_line >= region->Dimensions)
1428            focus_line = region->Dimensions - 1;
1429        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1430        queue_draw();
1431    }
1432    
1433    void DimRegionChooser::select_prev_dimension() {
1434        if (!region) return;
1435        focus_line--;
1436        if (focus_line < 0)
1437            focus_line = 0;
1438        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1439        queue_draw();
1440    }
1441    
1442    gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1443        if (!region) return NULL;
1444        return region->pDimensionRegions[maindimregno];
1445    }

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

  ViewVC Help
Powered by ViewVC