/[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 2626 by schoenebeck, Thu Jun 12 15:12:00 2014 UTC revision 3134 by schoenebeck, Fri Apr 28 12:41:12 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  // taken from gdk/gdkkeysyms.h  //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
35  // (define on demand, to avoid unnecessary dev lib package build dependency)  static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
36  #ifndef GDK_KEY_Control_L      DimensionCase dimCase;
 # define GDK_KEY_Control_L 0xffe3  
 #endif  
 #ifndef GDK_KEY_Control_R  
 # define GDK_KEY_Control_R 0xffe4  
 #endif  
   
 static std::map<gig::dimension_t,int> caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {  
     std::map<gig::dimension_t,int> dimCase;  
37      if (!dr) {      if (!dr) {
38          *isValidZone = false;          *isValidZone = false;
39          return dimCase;          return dimCase;
# Line 56  static std::map<gig::dimension_t,int> ca Line 51  static std::map<gig::dimension_t,int> ca
51      if (drIndex == 256) {      if (drIndex == 256) {
52          fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");          fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
53          *isValidZone = false;          *isValidZone = false;
54          return std::map<gig::dimension_t,int>();          return DimensionCase();
55      }      }
56    
57      for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {      for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
# Line 67  static std::map<gig::dimension_t,int> ca Line 62  static std::map<gig::dimension_t,int> ca
62          // there are also DimensionRegion objects of unused zones, skip them          // there are also DimensionRegion objects of unused zones, skip them
63          if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {          if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
64              *isValidZone = false;              *isValidZone = false;
65              return std::map<gig::dimension_t,int>();              return DimensionCase();
66          }          }
67      }      }
68    
# Line 76  static std::map<gig::dimension_t,int> ca Line 71  static std::map<gig::dimension_t,int> ca
71  }  }
72    
73  DimRegionChooser::DimRegionChooser(Gtk::Window& window) :  DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
74      red("#8070ff"),      red("#ff476e"),
75        blue("#4796ff"),
76      black("black"),      black("black"),
77      white("white")      white("white")
78  {  {
79        // make sure blue hatched pattern pixmap is loaded
80        loadBuiltInPix();
81    
82        // create blue hatched pattern
83        {
84            const int width = blueHatchedPattern->get_width();
85            const int height = blueHatchedPattern->get_height();
86            const int stride = blueHatchedPattern->get_rowstride();
87    
88            // manually convert from RGBA to ARGB
89            this->blueHatchedPatternARGB = blueHatchedPattern->copy();
90            const int pixelSize = stride / width;
91            const int totalPixels = width * height;
92            assert(pixelSize == 4);
93            unsigned char* ptr = this->blueHatchedPatternARGB->get_pixels();
94            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
95                const unsigned char r = ptr[0];
96                const unsigned char g = ptr[1];
97                const unsigned char b = ptr[2];
98                const unsigned char a = ptr[3];
99                ptr[0] = b;
100                ptr[1] = g;
101                ptr[2] = r;
102                ptr[3] = a;
103            }
104    
105            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
106                this->blueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
107            );
108            this->blueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
109            this->blueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
110        }
111    
112      instrument = 0;      instrument = 0;
113      region = 0;      region = 0;
114      maindimregno = -1;      maindimregno = -1;
115        maindimtype = gig::dimension_none; // initialize with invalid dimension type
116      focus_line = 0;      focus_line = 0;
117      resize.active = false;      resize.active = false;
118      cursor_is_resize = false;      cursor_is_resize = false;
119      h = 20;      h = 24;
120      multiSelectKeyDown = false;      multiSelectKeyDown = false;
121        primaryKeyDown = false;
122        shiftKeyDown = false;
123        modifybothchannels = modifyalldimregs = modifybothchannels = false;
124      set_can_focus();      set_can_focus();
125    
126        const Glib::ustring txtUseCheckBoxAllRegions =
127            _("Use checkbox 'all regions' to control whether this should apply to all regions.");
128    
129      actionGroup = Gtk::ActionGroup::create();      actionGroup = Gtk::ActionGroup::create();
130        actionSplitDimZone = Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
131        actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
132      actionGroup->add(      actionGroup->add(
133          Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone")),          actionSplitDimZone,
134          sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)          sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
135      );      );
136        actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
137        actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
138      actionGroup->add(      actionGroup->add(
139          Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone")),          actionDeleteDimZone,
140          sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)          sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
141      );      );
142    
# Line 141  DimRegionChooser::~DimRegionChooser() Line 181  DimRegionChooser::~DimRegionChooser()
181  {  {
182  }  }
183    
184    void DimRegionChooser::setModifyBothChannels(bool b) {
185        modifybothchannels = b;
186    }
187    
188    void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
189        modifyalldimregs = b;
190    }
191    
192    void DimRegionChooser::setModifyAllRegions(bool b) {
193        modifyallregions = b;
194    
195        actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
196        actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
197    }
198    
199  #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
200  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
201  {  {
# Line 229  bool DimRegionChooser::on_draw(const Cai Line 284  bool DimRegionChooser::on_draw(const Cai
284                      dstr = dstrbuf;                      dstr = dstrbuf;
285                      break;                      break;
286                  }                  }
                 layout->set_text(dstr);  
287    
288                    // Since bold font yields in larger label width, we first always
289                    // set the bold text variant, retrieve its dimensions (as worst
290                    // case dimensions of the label) ...
291                    layout->set_markup("<b>" + Glib::ustring(dstr) + "</b>");
292                  Pango::Rectangle rectangle = layout->get_logical_extents();                  Pango::Rectangle rectangle = layout->get_logical_extents();
293                    // ... and then reset the label to regular font style in case
294                    // the line is not selected. Otherwise the right hand side
295                    // actual dimension zones would jump around on selection change.
296                    bool isSelectedLine = (focus_line == i);
297                    if (!isSelectedLine)
298                        layout->set_markup(dstr);
299    
300                  double text_w = double(rectangle.get_width()) / Pango::SCALE;                  double text_w = double(rectangle.get_width()) / Pango::SCALE;
301                  if (text_w > maxwidth) maxwidth = text_w;                  if (text_w > maxwidth) maxwidth = text_w;
302    
# Line 273  bool DimRegionChooser::on_draw(const Cai Line 338  bool DimRegionChooser::on_draw(const Cai
338                  // draw focus rectangle around dimension's label and zones                  // draw focus rectangle around dimension's label and zones
339                  if (has_focus() && focus_line == i) {                  if (has_focus() && focus_line == i) {
340  #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
341                      Gdk::Rectangle farea(0, y, 150, 20);                      Gdk::Rectangle farea(0, y, 150, h);
342                      get_style()->paint_focus(get_window(), get_state(), farea,                      get_style()->paint_focus(get_window(), get_state(), farea,
343                                               *this, "",                                               *this, "",
344                                               0, y, label_width, 20);                                               0, y, label_width, h);
345  #else  #else
346                      get_style_context()->render_focus(cr,                      get_style_context()->render_focus(cr,
347                                                        0, y, label_width, 20);                                                        0, y, label_width, h);
348  #endif  #endif
349                  }                  }
350    
# Line 318  bool DimRegionChooser::on_draw(const Cai Line 383  bool DimRegionChooser::on_draw(const Cai
383                      cr->move_to(label_width + 0.5, y + 1);                      cr->move_to(label_width + 0.5, y + 1);
384                      cr->line_to(label_width + 0.5, y + h - 1);                      cr->line_to(label_width + 0.5, y + h - 1);
385                      int prevX = label_width;                      int prevX = label_width;
386                      int prevUpperLimit = 0;                      int prevUpperLimit = -1;
387    
388                      for (int j = 0 ; j < nbZones ; j++) {                      for (int j = 0 ; j < nbZones ; j++) {
389                          // draw dimension zone's borders for custom splits                          // draw dimension zone's borders for custom splits
# Line 338  bool DimRegionChooser::on_draw(const Cai Line 403  bool DimRegionChooser::on_draw(const Cai
403    
404                          // draw fill for zone                          // draw fill for zone
405                          bool isSelectedZone = this->dimzones[dimension].count(j);                          bool isSelectedZone = this->dimzones[dimension].count(j);
406                          Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);                          bool isMainSelection =
407                                this->maindimcase.find(dimension) != this->maindimcase.end() &&
408                                this->maindimcase[dimension] == j;
409                            if (isMainSelection)
410                                Gdk::Cairo::set_source_rgba(cr, blue);
411                            else if (isSelectedZone)
412                                cr->set_source(blueHatchedSurfacePattern);
413                            else
414                                Gdk::Cairo::set_source_rgba(cr, white);
415    
416                          cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);                          cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
417                          cr->fill();                          cr->fill();
418    
# Line 346  bool DimRegionChooser::on_draw(const Cai Line 420  bool DimRegionChooser::on_draw(const Cai
420                          // as numeric value to the user                          // as numeric value to the user
421                          {                          {
422                              Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                              Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
423                              layout->set_text(Glib::Ascii::dtostr(prevUpperLimit));                              layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
424                              Gdk::Cairo::set_source_rgba(cr, black);                              Gdk::Cairo::set_source_rgba(cr, black);
                             Pango::Rectangle rect = layout->get_logical_extents();  
425                              // get the text dimensions                              // get the text dimensions
426                              int text_width, text_height;                              int text_width, text_height;
427                              layout->get_pixel_size(text_width, text_height);                              layout->get_pixel_size(text_width, text_height);
428                              // move text to the left end of the dimension zone                              // move text to the left end of the dimension zone
429                              cr->move_to(prevX + 3, y + 1);                              cr->move_to(prevX + 3, y + (h - text_height) / 2);
430  #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
431                              pango_cairo_show_layout(cr->cobj(), layout->gobj());                              pango_cairo_show_layout(cr->cobj(), layout->gobj());
432  #else  #else
# Line 366  bool DimRegionChooser::on_draw(const Cai Line 439  bool DimRegionChooser::on_draw(const Cai
439                              Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                              Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
440                              layout->set_text(Glib::Ascii::dtostr(upperLimit));                              layout->set_text(Glib::Ascii::dtostr(upperLimit));
441                              Gdk::Cairo::set_source_rgba(cr, black);                              Gdk::Cairo::set_source_rgba(cr, black);
                             Pango::Rectangle rect = layout->get_logical_extents();  
442                              // get the text dimensions                              // get the text dimensions
443                              int text_width, text_height;                              int text_width, text_height;
444                              layout->get_pixel_size(text_width, text_height);                              layout->get_pixel_size(text_width, text_height);
445                              // move text to the left end of the dimension zone                              // move text to the left end of the dimension zone
446                              cr->move_to(x - 3 - text_width, y + 1);                              cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
447  #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
448                              pango_cairo_show_layout(cr->cobj(), layout->gobj());                              pango_cairo_show_layout(cr->cobj(), layout->gobj());
449  #else  #else
# Line 398  bool DimRegionChooser::on_draw(const Cai Line 470  bool DimRegionChooser::on_draw(const Cai
470                          if (j != 0) {                          if (j != 0) {
471                              // draw fill for zone                              // draw fill for zone
472                              bool isSelectedZone = this->dimzones[dimension].count(j-1);                              bool isSelectedZone = this->dimzones[dimension].count(j-1);
473                              Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);                              bool isMainSelection =
474                                    this->maindimcase.find(dimension) != this->maindimcase.end() &&
475                                    this->maindimcase[dimension] == (j-1);
476                                if (isMainSelection)
477                                    Gdk::Cairo::set_source_rgba(cr, blue);
478                                else if (isSelectedZone)
479                                    cr->set_source(blueHatchedSurfacePattern);
480                                else
481                                    Gdk::Cairo::set_source_rgba(cr, white);
482                              cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);                              cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
483                              cr->fill();                              cr->fill();
484    
# Line 408  bool DimRegionChooser::on_draw(const Cai Line 488  bool DimRegionChooser::on_draw(const Cai
488                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
489                                  layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));                                  layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
490                                  Gdk::Cairo::set_source_rgba(cr, black);                                  Gdk::Cairo::set_source_rgba(cr, black);
                                 Pango::Rectangle rect = layout->get_logical_extents();  
491                                  // get the text dimensions                                  // get the text dimensions
492                                  int text_width, text_height;                                  int text_width, text_height;
493                                  layout->get_pixel_size(text_width, text_height);                                  layout->get_pixel_size(text_width, text_height);
494                                  // move text to the left end of the dimension zone                                  // move text to the left end of the dimension zone
495                                  cr->move_to(prevX + 3, y + 1);                                  cr->move_to(prevX + 3, y + (h - text_height) / 2);
496  #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
497                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());
498  #else  #else
# Line 426  bool DimRegionChooser::on_draw(const Cai Line 505  bool DimRegionChooser::on_draw(const Cai
505                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
506                                  layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));                                  layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
507                                  Gdk::Cairo::set_source_rgba(cr, black);                                  Gdk::Cairo::set_source_rgba(cr, black);
                                 Pango::Rectangle rect = layout->get_logical_extents();  
508                                  // get the text dimensions                                  // get the text dimensions
509                                  int text_width, text_height;                                  int text_width, text_height;
510                                  layout->get_pixel_size(text_width, text_height);                                  layout->get_pixel_size(text_width, text_height);
511                                  // move text to the left end of the dimension zone                                  // move text to the left end of the dimension zone
512                                  cr->move_to(x - 3 - text_width, y + 1);                                  cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
513  #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
514                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());
515  #else  #else
# Line 469  void DimRegionChooser::set_region(gig::R Line 547  void DimRegionChooser::set_region(gig::R
547          }          }
548      }      }
549      dimregion_selected();      dimregion_selected();
550      set_size_request(800, region ? nbDimensions * 20 : 0);      set_size_request(800, region ? nbDimensions * h : 0);
551    
552      labels_changed = true;      labels_changed = true;
553      queue_resize();      queue_resize();
# Line 511  void DimRegionChooser::get_dimregions(co Line 589  void DimRegionChooser::get_dimregions(co
589    
590  void DimRegionChooser::update_after_resize()  void DimRegionChooser::update_after_resize()
591  {  {
592      if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {      const uint8_t upperLimit = resize.pos - 1;
593        gig::Instrument* instr = (gig::Instrument*)region->GetParent();
594    
595          int bitpos = 0;      int bitpos = 0;
596          for (int j = 0 ; j < resize.dimension ; j++) {      for (int j = 0 ; j < resize.dimension ; j++) {
597              bitpos += region->pDimensionDefinitions[j].bits;          bitpos += region->pDimensionDefinitions[j].bits;
598          }      }
599    
600        const int stereobitpos =
601            (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
602    
603        // the velocity dimension must be handled differently than all other
604        // dimension types, because
605        // 1. it is currently the only dimension type which allows different zone
606        //    sizes for different cases
607        // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
608        if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
609          int mask =          int mask =
610              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
611          int c = maindimregno & mask; // mask away this dimension          int c = maindimregno & mask; // mask away this dimension
# Line 542  void DimRegionChooser::update_after_resi Line 631  void DimRegionChooser::update_after_resi
631              }              }
632          }          }
633    
634          gig::DimensionRegion* d = region->pDimensionRegions[c + resize.offset];          int index = c + (resize.zone << bitpos);
635            gig::DimensionRegion* d = region->pDimensionRegions[index];
636          // update both v2 and v3 values          // update both v2 and v3 values
637          d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;          d->DimensionUpperLimits[resize.dimension] = upperLimit;
638          d->VelocityUpperLimit = resize.pos - 1;          d->VelocityUpperLimit = upperLimit;
639            if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
640                gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
641                d->DimensionUpperLimits[resize.dimension] = upperLimit;
642                d->VelocityUpperLimit = upperLimit;
643            }
644    
645            if (modifyalldimregs) {
646                gig::Region* rgn = NULL;
647                for (int key = 0; key < 128; ++key) {
648                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
649                    rgn = instr->GetRegion(key);
650                    if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
651                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
652                    if (!dimdef) continue;
653                    if (dimdef->zones != resize.dimensionDef.zones) continue;
654                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
655                    assert(iDim >= 0 && iDim < rgn->Dimensions);
656    
657                    // the dimension layout might be completely different in this
658                    // region, so we have to recalculate bitpos etc for this region
659                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
660                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
661                    const int selection = resize.zone << bitpos;
662    
663                    // primitive and inefficient loop implementation, however due to
664                    // this circumstance the loop code is much simpler, and its lack
665                    // of runtime efficiency should not be notable in practice
666                    for (int idr = 0; idr < 256; ++idr) {
667                        const int index = (idr & stencil) | selection;
668                        assert(index >= 0 && index < 256);
669                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
670                        if (!dr) continue;
671                        dr->DimensionUpperLimits[iDim] = upperLimit;
672                        d->VelocityUpperLimit = upperLimit;
673                    }
674                }
675            } else if (modifyallregions) { // implies modifyalldimregs is false ...
676                // resolve the precise case we need to modify for all other regions
677                DimensionCase dimCase = dimensionCaseOf(d);
678                // apply the velocity upper limit change to that resolved dim case
679                // of all regions ...
680                gig::Region* rgn = NULL;
681                for (int key = 0; key < 128; ++key) {
682                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
683                    rgn = instr->GetRegion(key);
684                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
685                    if (!dimdef) continue;
686                    if (dimdef->zones != resize.dimensionDef.zones) continue;
687                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
688                    assert(iDim >= 0 && iDim < rgn->Dimensions);
689    
690                    std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
691                    for (int i = 0; i < dimrgns.size(); ++i) {
692                        gig::DimensionRegion* dr = dimrgns[i];
693                        dr->DimensionUpperLimits[iDim] = upperLimit;
694                        dr->VelocityUpperLimit = upperLimit;
695                    }
696                }
697            }
698      } else {      } else {
699          for (int i = 0 ; i < region->DimensionRegions ; ) {          for (int i = 0 ; i < region->DimensionRegions ; ) {
   
700              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
701                  // the dimension didn't previously have custom                  // the dimension didn't previously have custom
702                  // limits, so we have to set default limits for                  // limits, so we have to set default limits for
703                  // all the dimension regions                  // all the dimension regions
                 int bitpos = 0;  
                 for (int j = 0 ; j < resize.dimension ; j++) {  
                     bitpos += region->pDimensionDefinitions[j].bits;  
                 }  
704                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
705    
706                  for (int j = 0 ; j < nbZones ; j++) {                  for (int j = 0 ; j < nbZones ; j++) {
# Line 565  void DimRegionChooser::update_after_resi Line 708  void DimRegionChooser::update_after_resi
708                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
709                  }                  }
710              }              }
711              gig::DimensionRegion* d = region->pDimensionRegions[i + resize.offset];              int index = i + (resize.zone << bitpos);
712              d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              gig::DimensionRegion* d = region->pDimensionRegions[index];
713                d->DimensionUpperLimits[resize.dimension] = upperLimit;
714    #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
715                if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
716                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
717                    d->DimensionUpperLimits[resize.dimension] = upperLimit;
718                }
719    #endif
720              int bitpos = 0;              int bitpos = 0;
721              int j;              int j;
722              for (j = 0 ; j < region->Dimensions ; j++) {              for (j = 0 ; j < region->Dimensions ; j++) {
# Line 581  void DimRegionChooser::update_after_resi Line 730  void DimRegionChooser::update_after_resi
730              if (j == region->Dimensions) break;              if (j == region->Dimensions) break;
731              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
732          }          }
733    
734            if (modifyallregions) { // TODO: this code block could be merged with the similar (and more generalized) code block of the velocity dimension above
735                gig::Region* rgn = NULL;
736                for (int key = 0; key < 128; ++key) {
737                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
738                    rgn = instr->GetRegion(key);
739                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
740                    if (!dimdef) continue;
741                    if (dimdef->zones != resize.dimensionDef.zones) continue;
742                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
743                    assert(iDim >= 0 && iDim < rgn->Dimensions);
744    
745                    // the dimension layout might be completely different in this
746                    // region, so we have to recalculate bitpos etc for this region
747                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
748                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
749                    const int selection = resize.zone << bitpos;
750    
751                    // this loop implementation is less efficient than the above's
752                    // loop implementation (which skips unnecessary dimension regions)
753                    // however this code is much simpler, and its lack of runtime
754                    // efficiency should not be notable in practice
755                    for (int idr = 0; idr < 256; ++idr) {
756                        const int index = (idr & stencil) | selection;
757                        assert(index >= 0 && index < 256);
758                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
759                        if (!dr) continue;
760                        dr->DimensionUpperLimits[iDim] = upperLimit;
761                    }
762                }
763            }
764      }      }
765  }  }
766    
# Line 809  bool DimRegionChooser::is_in_resize_zone Line 989  bool DimRegionChooser::is_in_resize_zone
989                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
990                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
991                      resize.dimension = dim;                      resize.dimension = dim;
992                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
993                        resize.zone = iZone;
994                      resize.pos = limit;                      resize.pos = limit;
995                      resize.min = prev_limit;                      resize.min = prev_limit;
996    
# Line 850  sigc::signal<void>& DimRegionChooser::si Line 1031  sigc::signal<void>& DimRegionChooser::si
1031    
1032  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
1033  {  {
1034      // 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
1035      // fokus.      // to set focus
1036      if (direction == Gtk::DIR_TAB_FORWARD ||      if (direction == Gtk::DIR_TAB_FORWARD ||
1037          direction == Gtk::DIR_DOWN) {          direction == Gtk::DIR_DOWN) {
1038          if (!has_focus()) {          if (!has_focus()) {
# Line 883  bool DimRegionChooser::on_focus(Gtk::Dir Line 1064  bool DimRegionChooser::on_focus(Gtk::Dir
1064              }              }
1065          }          }
1066      } else if (!has_focus()) {      } else if (!has_focus()) {
1067          // TODO: kolla att focus_line finns!          // TODO: check that focus_line exists
1068          grab_focus();          grab_focus();
1069          return true;          return true;
1070      } else {      } else {
1071          // TODO: öka eller minska värde!          // TODO: increase or decrease value
1072      }      }
1073        return false;
1074  }  }
1075    
1076  void DimRegionChooser::split_dimension_zone() {      void DimRegionChooser::split_dimension_zone() {    
1077      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1078      try {      try {
1079          region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);          if (!modifyallregions) {
1080                region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1081            } else {
1082                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1083                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1084                assert(pMaindimdef != NULL);
1085                // retain structure by value since the original region will be
1086                // modified in the loop below as well
1087                gig::dimension_def_t maindimdef = *pMaindimdef;
1088                std::vector<gig::Region*> ignoredAll;
1089                std::vector<gig::Region*> ignoredMinor;
1090                std::vector<gig::Region*> ignoredCritical;
1091                gig::Region* rgn = NULL;
1092                for (int key = 0; key < 128; ++key) {
1093                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1094                    rgn = instr->GetRegion(key);
1095    
1096                    // ignore all regions which do not exactly match the dimension
1097                    // layout of the selected region where this operation was emitted
1098                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1099                    if (!dimdef) {
1100                        ignoredAll.push_back(rgn);
1101                        ignoredMinor.push_back(rgn);
1102                        continue;
1103                    }
1104                    if (dimdef->zones != maindimdef.zones) {
1105                        ignoredAll.push_back(rgn);
1106                        ignoredCritical.push_back(rgn);
1107                        continue;
1108                    }
1109    
1110                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1111                }
1112                if (!ignoredAll.empty()) {
1113                    Glib::ustring txt;
1114                    if (ignoredCritical.empty())
1115                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1116                    else if (ignoredMinor.empty())
1117                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1118                    else
1119                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1120                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1121                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1122                    Gtk::MessageDialog msg(txt, false, type);
1123                    msg.run();
1124                }
1125            }
1126      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1127          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1128          msg.run();          msg.run();
# Line 909  void DimRegionChooser::split_dimension_z Line 1137  void DimRegionChooser::split_dimension_z
1137  void DimRegionChooser::delete_dimension_zone() {  void DimRegionChooser::delete_dimension_zone() {
1138      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1139      try {      try {
1140          region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);          if (!modifyallregions) {
1141                region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1142            } else {
1143                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1144                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1145                assert(pMaindimdef != NULL);
1146                // retain structure by value since the original region will be
1147                // modified in the loop below as well
1148                gig::dimension_def_t maindimdef = *pMaindimdef;
1149                std::vector<gig::Region*> ignoredAll;
1150                std::vector<gig::Region*> ignoredMinor;
1151                std::vector<gig::Region*> ignoredCritical;
1152                gig::Region* rgn = NULL;
1153                for (int key = 0; key < 128; ++key) {
1154                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1155                    rgn = instr->GetRegion(key);
1156    
1157                    // ignore all regions which do not exactly match the dimension
1158                    // layout of the selected region where this operation was emitted
1159                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1160                    if (!dimdef) {
1161                        ignoredAll.push_back(rgn);
1162                        ignoredMinor.push_back(rgn);
1163                        continue;
1164                    }
1165                    if (dimdef->zones != maindimdef.zones) {
1166                        ignoredAll.push_back(rgn);
1167                        ignoredCritical.push_back(rgn);
1168                        continue;
1169                    }
1170    
1171                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1172                }
1173                if (!ignoredAll.empty()) {
1174                    Glib::ustring txt;
1175                    if (ignoredCritical.empty())
1176                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1177                    else if (ignoredMinor.empty())
1178                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1179                    else
1180                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1181                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1182                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1183                    Gtk::MessageDialog msg(txt, false, type);
1184                    msg.run();
1185                }
1186            }
1187      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1188          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1189          msg.run();          msg.run();
# Line 921  void DimRegionChooser::delete_dimension_ Line 1195  void DimRegionChooser::delete_dimension_
1195      refresh_all();      refresh_all();
1196  }  }
1197    
1198    // Cmd key on Mac, Ctrl key on all other OSs
1199    static const guint primaryKeyL =
1200        #if defined(__APPLE__)
1201        GDK_KEY_Meta_L;
1202        #else
1203        GDK_KEY_Control_L;
1204        #endif
1205    
1206    static const guint primaryKeyR =
1207        #if defined(__APPLE__)
1208        GDK_KEY_Meta_R;
1209        #else
1210        GDK_KEY_Control_R;
1211        #endif
1212    
1213  bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {  bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1214      //printf("key down\n");      //printf("key down 0x%x\n", key->keyval);
1215      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1216          multiSelectKeyDown = true;          multiSelectKeyDown = true;
1217        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1218            primaryKeyDown = true;
1219        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1220            shiftKeyDown = true;
1221    
1222        //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
1223        /*if (key->keyval == GDK_KEY_Left)
1224            select_prev_dimzone();
1225        if (key->keyval == GDK_KEY_Right)
1226            select_next_dimzone();
1227        if (key->keyval == GDK_KEY_Up)
1228            select_prev_dimension();
1229        if (key->keyval == GDK_KEY_Down)
1230            select_next_dimension();*/
1231        return false;
1232  }  }
1233    
1234  bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {  bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1235      //printf("key up\n");      //printf("key up 0x%x\n", key->keyval);
1236      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1237          multiSelectKeyDown = false;          multiSelectKeyDown = false;
1238        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1239            primaryKeyDown = false;
1240        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1241            shiftKeyDown = false;
1242    
1243        if (!has_focus()) return false;
1244    
1245        // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow
1246        // (which is supposed to switch between regions)
1247        if (primaryKeyDown) return false;
1248    
1249        // avoid conflict with Alt+Shift+Left and Alt+Shift+Right accelerators on
1250        // mainwindow
1251        if (shiftKeyDown) return false;
1252    
1253        if (key->keyval == GDK_KEY_Left)
1254            select_prev_dimzone();
1255        if (key->keyval == GDK_KEY_Right)
1256            select_next_dimzone();
1257        if (key->keyval == GDK_KEY_Up)
1258            select_prev_dimension();
1259        if (key->keyval == GDK_KEY_Down)
1260            select_next_dimension();
1261    
1262        return false;
1263    }
1264    
1265    void DimRegionChooser::resetSelectedZones() {
1266        this->dimzones.clear();
1267        if (!region) {
1268            queue_draw(); // redraw required parts
1269            return;
1270        }
1271        if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1272            queue_draw(); // redraw required parts
1273            return;
1274        }
1275        if (!region->pDimensionRegions[maindimregno]) {
1276            queue_draw(); // redraw required parts
1277            return;
1278        }
1279        gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1280    
1281        bool isValidZone;
1282        this->maindimcase = dimensionCaseOf(dimrgn);
1283    
1284        for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1285             it != this->maindimcase.end(); ++it)
1286        {
1287            this->dimzones[it->first].insert(it->second);
1288        }
1289    
1290        // redraw required parts
1291        queue_draw();
1292    }
1293    
1294    bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1295        if (!region) return false; //.selection failed
1296    
1297        for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1298            if (region->pDimensionRegions[dr] == dimrgn) {
1299                // reset dim region zone selection to the requested specific dim region case
1300                maindimregno = dr;
1301                resetSelectedZones();
1302    
1303                // emit signal that dimregion selection has changed, for external entities
1304                dimregion_selected();
1305    
1306                return true; // selection success
1307            }
1308        }
1309    
1310        return false; //.selection failed
1311    }
1312    
1313    void DimRegionChooser::select_next_dimzone(bool add) {
1314        select_dimzone_by_dir(+1, add);
1315    }
1316    
1317    void DimRegionChooser::select_prev_dimzone(bool add) {
1318        select_dimzone_by_dir(-1, add);
1319    }
1320    
1321    void DimRegionChooser::select_dimzone_by_dir(int dir, bool add) {
1322        if (!region) return;
1323        if (!region->Dimensions) return;
1324        if (focus_line < 0) focus_line = 0;
1325        if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1326    
1327        maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1328        if (maindimtype == gig::dimension_none) {
1329            printf("maindimtype -> none\n");
1330            return;
1331        }
1332    
1333        if (maindimcase.empty()) {
1334            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1335            if (maindimcase.empty()) {
1336                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1337                return;
1338            }
1339        }
1340    
1341        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1342        if (z < 0) z = 0;
1343        if (z >= region->pDimensionDefinitions[focus_line].zones)
1344            z = region->pDimensionDefinitions[focus_line].zones - 1;
1345    
1346        maindimcase[maindimtype] = z;
1347    
1348        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1349        if (!dr) {
1350            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1351            return;
1352        }
1353    
1354        maindimregno = getDimensionRegionIndex(dr);
1355    
1356        if (!add) {
1357            // reset selected dimregion zones
1358            dimzones.clear();
1359        }
1360        for (DimensionCase::const_iterator it = maindimcase.begin();
1361             it != maindimcase.end(); ++it)
1362        {
1363            dimzones[it->first].insert(it->second);
1364        }
1365    
1366        dimregion_selected();
1367    
1368        // disabled: would overwrite dimregno with wrong value
1369        //refresh_all();
1370        // so requesting just a raw repaint instead:
1371        queue_draw();
1372    }
1373    
1374    void DimRegionChooser::select_next_dimension() {
1375        if (!region) return;
1376        focus_line++;
1377        if (focus_line >= region->Dimensions)
1378            focus_line = region->Dimensions - 1;
1379        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1380        queue_draw();
1381    }
1382    
1383    void DimRegionChooser::select_prev_dimension() {
1384        if (!region) return;
1385        focus_line--;
1386        if (focus_line < 0)
1387            focus_line = 0;
1388        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1389        queue_draw();
1390  }  }
1391    
1392  gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {  gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {

Legend:
Removed from v.2626  
changed lines
  Added in v.3134

  ViewVC Help
Powered by ViewVC