/[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 2246 by persson, Fri Aug 19 10:55:41 2011 UTC revision 3286 by schoenebeck, Thu Jun 22 10:54:10 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2011 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 "global.h"
21    #include <gtkmm/box.h>
22  #include "dimregionchooser.h"  #include "dimregionchooser.h"
23  #include <cairomm/context.h>  #include <cairomm/context.h>
24    #include <cairomm/surface.h>
25  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
26  #include <gdkmm/general.h>  #include <gdkmm/general.h>
27    #include <glibmm/stringutils.h>
28    #include <gtkmm/stock.h>
29    #include <glibmm/ustring.h>
30    #include <gtkmm/messagedialog.h>
31    #include <assert.h>
32    
33    #include "gfx/builtinpix.h"
34    
35    //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
36    static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
37        DimensionCase dimCase;
38        if (!dr) {
39            *isValidZone = false;
40            return dimCase;
41        }
42    
43  #include "global.h"      gig::Region* rgn = (gig::Region*) dr->GetParent();
44    
45  DimRegionChooser::DimRegionChooser() :      // find the dimension region index of the passed dimension region
46      red("#8070ff"),      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 1
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 blue hatched pattern 2
114        {
115            const int width = blueHatchedPattern2->get_width();
116            const int height = blueHatchedPattern2->get_height();
117            const int stride = blueHatchedPattern2->get_rowstride();
118    
119            // manually convert from RGBA to ARGB
120            this->blueHatchedPattern2ARGB = blueHatchedPattern2->copy();
121            const int pixelSize = stride / width;
122            const int totalPixels = width * height;
123            assert(pixelSize == 4);
124            unsigned char* ptr = this->blueHatchedPattern2ARGB->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->blueHatchedPattern2ARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
138            );
139            this->blueHatchedSurfacePattern2 = Cairo::SurfacePattern::create(imageSurface);
140            this->blueHatchedSurfacePattern2->set_extend(Cairo::EXTEND_REPEAT);
141        }
142    
143        // create gray blue hatched pattern
144        {
145            const int width = grayBlueHatchedPattern->get_width();
146            const int height = grayBlueHatchedPattern->get_height();
147            const int stride = grayBlueHatchedPattern->get_rowstride();
148    
149            // manually convert from RGBA to ARGB
150            this->grayBlueHatchedPatternARGB = grayBlueHatchedPattern->copy();
151            const int pixelSize = stride / width;
152            const int totalPixels = width * height;
153            assert(pixelSize == 4);
154            unsigned char* ptr = this->grayBlueHatchedPatternARGB->get_pixels();
155            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
156                const unsigned char r = ptr[0];
157                const unsigned char g = ptr[1];
158                const unsigned char b = ptr[2];
159                const unsigned char a = ptr[3];
160                ptr[0] = b;
161                ptr[1] = g;
162                ptr[2] = r;
163                ptr[3] = a;
164            }
165    
166            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
167                this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
168            );
169            this->grayBlueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
170            this->grayBlueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
171        }
172    
173      instrument = 0;      instrument = 0;
174      region = 0;      region = 0;
175      dimregno = -1;      maindimregno = -1;
176        maindimtype = gig::dimension_none; // initialize with invalid dimension type
177      focus_line = 0;      focus_line = 0;
178      resize.active = false;      resize.active = false;
179      cursor_is_resize = false;      cursor_is_resize = false;
180      h = 20;      h = 24;
181        multiSelectKeyDown = false;
182        primaryKeyDown = false;
183        shiftKeyDown = false;
184        modifybothchannels = modifyalldimregs = modifybothchannels = false;
185      set_can_focus();      set_can_focus();
186    
187        const Glib::ustring txtUseCheckBoxAllRegions =
188            _("Use checkbox 'all regions' to control whether this should apply to all regions.");
189    
190        actionGroup = Gtk::ActionGroup::create();
191        actionSplitDimZone = Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
192        actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
193        actionGroup->add(
194            actionSplitDimZone,
195            sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
196        );
197        actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
198        actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
199        actionGroup->add(
200            actionDeleteDimZone,
201            sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
202        );
203    
204        uiManager = Gtk::UIManager::create();
205        uiManager->insert_action_group(actionGroup);
206        Glib::ustring ui_info =
207            "<ui>"
208            "  <popup name='PopupMenuInsideDimRegion'>"
209            "    <menuitem action='SplitDimZone'/>"
210            "    <menuitem action='DeleteDimZone'/>"
211            "  </popup>"
212    //         "  <popup name='PopupMenuOutsideDimRegion'>"
213    //         "    <menuitem action='Add'/>"
214    //         "  </popup>"
215            "</ui>";
216        uiManager->add_ui_from_string(ui_info);
217    
218        popup_menu_inside_dimregion = dynamic_cast<Gtk::Menu*>(
219            uiManager->get_widget("/PopupMenuInsideDimRegion"));
220    //     popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(
221    //         uiManager->get_widget("/PopupMenuOutsideDimRegion"));
222    
223      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
224                 Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_HINT_MASK);
225    
     for (int i = 0 ; i < 256 ; i++) dimvalue[i] = 0;  
226      labels_changed = true;      labels_changed = true;
227    
228        set_tooltip_text(_(
229            "Right click here for options on altering dimension zones. Press and "
230            "hold CTRL key for selecting multiple dimension zones simultaniously."
231        ));
232        
233        window.signal_key_press_event().connect(
234            sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)
235        );
236        window.signal_key_release_event().connect(
237            sigc::mem_fun(*this, &DimRegionChooser::onKeyReleased)
238        );
239  }  }
240    
241  DimRegionChooser::~DimRegionChooser()  DimRegionChooser::~DimRegionChooser()
242  {  {
243  }  }
244    
245    void DimRegionChooser::setModifyBothChannels(bool b) {
246        modifybothchannels = b;
247        // redraw required parts
248        queue_draw();
249    }
250    
251    void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
252        modifyalldimregs = b;
253        // redraw required parts
254        queue_draw();
255    }
256    
257    void DimRegionChooser::setModifyAllRegions(bool b) {
258        modifyallregions = b;
259    
260        actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
261        actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
262    
263        // redraw required parts
264        queue_draw();
265    }
266    
267  #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
268  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
269  {  {
# Line 58  bool DimRegionChooser::on_expose_event(G Line 274  bool DimRegionChooser::on_expose_event(G
274    
275      const Cairo::RefPtr<Cairo::Context>& cr =      const Cairo::RefPtr<Cairo::Context>& cr =
276          get_window()->create_cairo_context();          get_window()->create_cairo_context();
 #if 0  
 }  
 #endif  
277  #else  #else
278  bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)  bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
279  {  {
# Line 139  bool DimRegionChooser::on_draw(const Cai Line 352  bool DimRegionChooser::on_draw(const Cai
352                      dstr = dstrbuf;                      dstr = dstrbuf;
353                      break;                      break;
354                  }                  }
                 layout->set_text(dstr);  
355    
356                    // Since bold font yields in larger label width, we first always
357                    // set the bold text variant, retrieve its dimensions (as worst
358                    // case dimensions of the label) ...
359                    layout->set_markup("<b>" + Glib::ustring(dstr) + "</b>");
360                  Pango::Rectangle rectangle = layout->get_logical_extents();                  Pango::Rectangle rectangle = layout->get_logical_extents();
361                    // ... and then reset the label to regular font style in case
362                    // the line is not selected. Otherwise the right hand side
363                    // actual dimension zones would jump around on selection change.
364                    bool isSelectedLine = (focus_line == i);
365                    if (!isSelectedLine)
366                        layout->set_markup(dstr);
367    
368                  double text_w = double(rectangle.get_width()) / Pango::SCALE;                  double text_w = double(rectangle.get_width()) / Pango::SCALE;
369                  if (text_w > maxwidth) maxwidth = text_w;                  if (text_w > maxwidth) maxwidth = text_w;
370    
# Line 176  bool DimRegionChooser::on_draw(const Cai Line 399  bool DimRegionChooser::on_draw(const Cai
399      for (int i = 0 ; i < region->Dimensions ; i++) {      for (int i = 0 ; i < region->Dimensions ; i++) {
400          int nbZones = region->pDimensionDefinitions[i].zones;          int nbZones = region->pDimensionDefinitions[i].zones;
401          if (nbZones) {          if (nbZones) {
402                const gig::dimension_t dimension = region->pDimensionDefinitions[i].dimension;
403    
404              if (y >= clipy2) break;              if (y >= clipy2) break;
405              if (y + h > clipy1) {              if (y + h > clipy1) {
406                  // draw focus rectangle around dimension's label and zones                  // draw focus rectangle around dimension's label and zones
407                  if (has_focus() && focus_line == i) {                  if (has_focus() && focus_line == i) {
408  #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
409                      Gdk::Rectangle farea(0, y, 150, 20);                      Gdk::Rectangle farea(0, y, 150, h);
410                      get_style()->paint_focus(get_window(), get_state(), farea,                      get_style()->paint_focus(get_window(), get_state(), farea,
411                                               *this, "",                                               *this, "",
412                                               0, y, label_width, 20);                                               0, y, label_width, h);
413  #else  #else
414                      get_style_context()->render_focus(cr,                      get_style_context()->render_focus(cr,
415                                                        0, y, label_width, 20);                                                        0, y, label_width, h);
416  #endif  #endif
417                  }                  }
418    
# Line 206  bool DimRegionChooser::on_draw(const Cai Line 431  bool DimRegionChooser::on_draw(const Cai
431                  cr->fill();                  cr->fill();
432    
433                  int c = 0;                  int c = 0;
434                  if (dimregno >= 0) {                  if (maindimregno >= 0) {
435                      int mask =                      int mask =
436                          ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<                          ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
437                            bitpos);                            bitpos);
438                      c = dimregno & mask; // mask away this dimension                      c = maindimregno & mask; // mask away this dimension
439                  }                  }
440                  bool customsplits =                  bool customsplits =
441                      ((region->pDimensionDefinitions[i].split_type ==                      ((region->pDimensionDefinitions[i].split_type ==
# Line 220  bool DimRegionChooser::on_draw(const Cai Line 445  bool DimRegionChooser::on_draw(const Cai
445                        gig::dimension_velocity &&                        gig::dimension_velocity &&
446                        region->pDimensionRegions[c]->VelocityUpperLimit));                        region->pDimensionRegions[c]->VelocityUpperLimit));
447    
448                  // draw dimension's zone borders                  // draw dimension zones
449                  Gdk::Cairo::set_source_rgba(cr, black);                  Gdk::Cairo::set_source_rgba(cr, black);
450                  if (customsplits) {                  if (customsplits) {
451                      cr->move_to(label_width + 0.5, y + 1);                      cr->move_to(label_width + 0.5, y + 1);
452                      cr->line_to(label_width + 0.5, y + h - 1);                      cr->line_to(label_width + 0.5, y + h - 1);
453                        int prevX = label_width;
454                        int prevUpperLimit = -1;
455    
456                      for (int j = 0 ; j < nbZones ; j++) {                      for (int j = 0 ; j < nbZones ; j++) {
457                            // draw dimension zone's borders for custom splits
458                          gig::DimensionRegion* d =                          gig::DimensionRegion* d =
459                              region->pDimensionRegions[c + (j << bitpos)];                              region->pDimensionRegions[c + (j << bitpos)];
460                          int upperLimit = d->DimensionUpperLimits[i];                          int upperLimit = d->DimensionUpperLimits[i];
# Line 236  bool DimRegionChooser::on_draw(const Cai Line 464  bool DimRegionChooser::on_draw(const Cai
464                              label_width;                              label_width;
465                          if (x >= clipx2) break;                          if (x >= clipx2) break;
466                          if (x < clipx1) continue;                          if (x < clipx1) continue;
467                            Gdk::Cairo::set_source_rgba(cr, black);
468                          cr->move_to(x + 0.5, y + 1);                          cr->move_to(x + 0.5, y + 1);
469                          cr->line_to(x + 0.5, y + h - 1);                          cr->line_to(x + 0.5, y + h - 1);
470                            cr->stroke();
471    
472                            // draw fill for zone
473                            bool isSelectedZone = this->dimzones[dimension].count(j);
474                            bool isMainSelection =
475                                this->maindimcase.find(dimension) != this->maindimcase.end() &&
476                                this->maindimcase[dimension] == j;
477                            bool isCheckBoxSelected =
478                                modifyalldimregs ||
479                                (modifybothchannels &&
480                                    dimension == gig::dimension_samplechannel);
481                            if (isMainSelection)
482                                Gdk::Cairo::set_source_rgba(cr, blue);
483                            else if (isSelectedZone)
484                                cr->set_source(blueHatchedSurfacePattern2);
485                            else if (isCheckBoxSelected)
486                                cr->set_source(blueHatchedSurfacePattern);
487                            else
488                                Gdk::Cairo::set_source_rgba(cr, white);
489    
490                            cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
491                            cr->fill();
492    
493                            // draw text showing the beginning of the dimension zone
494                            // as numeric value to the user
495                            {
496                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
497                                layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
498                                Gdk::Cairo::set_source_rgba(cr, black);
499                                // get the text dimensions
500                                int text_width, text_height;
501                                layout->get_pixel_size(text_width, text_height);
502                                // move text to the left end of the dimension zone
503                                cr->move_to(prevX + 3, y + (h - text_height) / 2);
504    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
505                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
506    #else
507                                layout->show_in_cairo_context(cr);
508    #endif
509                            }
510                            // draw text showing the end of the dimension zone
511                            // as numeric value to the user
512                            {
513                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
514                                layout->set_text(Glib::Ascii::dtostr(upperLimit));
515                                Gdk::Cairo::set_source_rgba(cr, black);
516                                // get the text dimensions
517                                int text_width, text_height;
518                                layout->get_pixel_size(text_width, text_height);
519                                // move text to the left end of the dimension zone
520                                cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
521    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
522                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
523    #else
524                                layout->show_in_cairo_context(cr);
525    #endif
526                            }
527    
528                            prevX = x;
529                            prevUpperLimit = upperLimit;
530                      }                      }
531                  } else {                  } else {
532                        int prevX = 0;
533                      for (int j = 0 ; j <= nbZones ; j++) {                      for (int j = 0 ; j <= nbZones ; j++) {
534                            // draw dimension zone's borders for normal splits
535                          int x = int((w - label_width - 1) * j /                          int x = int((w - label_width - 1) * j /
536                                      double(nbZones) + 0.5) + label_width;                                      double(nbZones) + 0.5) + label_width;
537                          if (x >= clipx2) break;                          if (x >= clipx2) break;
538                          if (x < clipx1) continue;                          if (x < clipx1) continue;
539                            Gdk::Cairo::set_source_rgba(cr, black);
540                          cr->move_to(x + 0.5, y + 1);                          cr->move_to(x + 0.5, y + 1);
541                          cr->line_to(x + 0.5, y + h - 1);                          cr->line_to(x + 0.5, y + h - 1);
542                      }                          cr->stroke();
                 }  
                 cr->stroke();  
543    
544                  // draw fill for currently selected zone                          if (j != 0) {
545                  if (dimregno >= 0) {                              // draw fill for zone
546                      Gdk::Cairo::set_source_rgba(cr, red);                              bool isSelectedZone = this->dimzones[dimension].count(j-1);
547                      int dr = (dimregno >> bitpos) &                              bool isMainSelection =
548                          ((1 << region->pDimensionDefinitions[i].bits) - 1);                                  this->maindimcase.find(dimension) != this->maindimcase.end() &&
549                      if (customsplits) {                                  this->maindimcase[dimension] == (j-1);
550                          int x1 = label_width;                              bool isCheckBoxSelected =
551                          for (int j = 0 ; j < nbZones && x1 + 1 < clipx2 ; j++) {                                  modifyalldimregs ||
552                              gig::DimensionRegion* d =                                  (modifybothchannels &&
553                                  region->pDimensionRegions[c + (j << bitpos)];                                      dimension == gig::dimension_samplechannel);
554                              int upperLimit = d->DimensionUpperLimits[i];                              if (isMainSelection)
555                              if (!upperLimit) {                                  Gdk::Cairo::set_source_rgba(cr, blue);
556                                  upperLimit = d->VelocityUpperLimit;                              else if (isSelectedZone)
557                                    cr->set_source(blueHatchedSurfacePattern2);
558                                else if (isCheckBoxSelected)
559                                    cr->set_source(blueHatchedSurfacePattern);
560                                else
561                                    Gdk::Cairo::set_source_rgba(cr, white);
562                                cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
563                                cr->fill();
564    
565                                // draw text showing the beginning of the dimension zone
566                                // as numeric value to the user
567                                {
568                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
569                                    layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
570                                    Gdk::Cairo::set_source_rgba(cr, black);
571                                    // get the text dimensions
572                                    int text_width, text_height;
573                                    layout->get_pixel_size(text_width, text_height);
574                                    // move text to the left end of the dimension zone
575                                    cr->move_to(prevX + 3, y + (h - text_height) / 2);
576    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
577                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
578    #else
579                                    layout->show_in_cairo_context(cr);
580    #endif
581                              }                              }
582                              int v = upperLimit + 1;                              // draw text showing the end of the dimension zone
583                              int x2 = int((w - label_width - 1) * v / 128.0 +                              // as numeric value to the user
584                                           0.5) + label_width;                              {
585                              if (j == dr && x1 < x2) {                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
586                                  cr->rectangle(x1 + 1, y + 1,                                  layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
587                                                (x2 - x1) - 1, h - 2);                                  Gdk::Cairo::set_source_rgba(cr, black);
588                                  cr->fill();                                  // get the text dimensions
589                                  break;                                  int text_width, text_height;
590                                    layout->get_pixel_size(text_width, text_height);
591                                    // move text to the left end of the dimension zone
592                                    cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
593    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
594                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
595    #else
596                                    layout->show_in_cairo_context(cr);
597    #endif
598                              }                              }
                             x1 = x2;  
599                          }                          }
600                      } else {                          prevX = x;
601                          if (dr < nbZones) {                      }      
                             int x1 = int((w - label_width - 1) * dr /  
                                          double(nbZones) + 0.5);  
                             int 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);  
                             cr->fill();  
                         }  
                     }  
602                  }                  }
603              }              }
   
604              y += h;              y += h;
605          }          }
606          bitpos += region->pDimensionDefinitions[i].bits;          bitpos += region->pDimensionDefinitions[i].bits;
# Line 301  bool DimRegionChooser::on_draw(const Cai Line 612  bool DimRegionChooser::on_draw(const Cai
612  void DimRegionChooser::set_region(gig::Region* region)  void DimRegionChooser::set_region(gig::Region* region)
613  {  {
614      this->region = region;      this->region = region;
615      dimregno = 0;      maindimregno = 0;
616      nbDimensions = 0;      nbDimensions = 0;
617      if (region) {      if (region) {
618          int bitcount = 0;          int bitcount = 0;
# Line 309  void DimRegionChooser::set_region(gig::R Line 620  void DimRegionChooser::set_region(gig::R
620              if (region->pDimensionDefinitions[dim].bits == 0) continue;              if (region->pDimensionDefinitions[dim].bits == 0) continue;
621              nbDimensions++;              nbDimensions++;
622    
623              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
624                               region->pDimensionDefinitions[dim].zones - 1);                               region->pDimensionDefinitions[dim].zones - 1);
625              dimregno |= (z << bitcount);              maindimregno |= (z << bitcount);
626              bitcount += region->pDimensionDefinitions[dim].bits;              bitcount += region->pDimensionDefinitions[dim].bits;
627          }          }
         dimreg = region->pDimensionRegions[dimregno];  
     } else {  
         dimreg = 0;  
628      }      }
629      dimregion_selected();      dimregion_selected();
630      set_size_request(800, region ? nbDimensions * 20 : 0);      set_size_request(800, region ? nbDimensions * h : 0);
631    
632      labels_changed = true;      labels_changed = true;
633      queue_resize();      queue_resize();
634        queue_draw();
635  }  }
636    
637    void DimRegionChooser::refresh_all() {
638        set_region(region);
639    }
640    
641  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
642                                        std::set<gig::DimensionRegion*>& dimregs) const                                        std::set<gig::DimensionRegion*>& dimregs) const
643  {  {
644      int dimregno = 0;      for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
645      int bitcount = 0;          gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
646      int stereo_bit = 0;          if (!dimRgn) continue;
647      for (int dim = 0 ; dim < region->Dimensions ; dim++) {          bool isValidZone;
648          if (region->pDimensionDefinitions[dim].bits == 0) continue;          std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
649          if (stereo &&          if (!isValidZone) continue;
650              region->pDimensionDefinitions[dim].dimension == gig::dimension_samplechannel) {          for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
651              stereo_bit = (1 << bitcount);               it != dimCase.end(); ++it)
652          } else {          {
653              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
654                               region->pDimensionDefinitions[dim].zones - 1);  
655              dimregno |= (z << bitcount);              std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
656                    this->dimzones.find(it->first);
657                if (itSelectedDimension != this->dimzones.end() &&
658                    itSelectedDimension->second.count(it->second)) continue; // is selected
659    
660                goto notSelected;
661          }          }
662          bitcount += region->pDimensionDefinitions[dim].bits;  
663            dimregs.insert(dimRgn);
664    
665            notSelected:
666            ;
667      }      }
     dimregs.insert(region->pDimensionRegions[dimregno]);  
     if (stereo_bit) dimregs.insert(region->pDimensionRegions[dimregno | stereo_bit]);  
668  }  }
669    
670  void DimRegionChooser::update_after_resize()  void DimRegionChooser::update_after_resize()
671  {  {
672      if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {      const uint8_t upperLimit = resize.pos - 1;
673        gig::Instrument* instr = (gig::Instrument*)region->GetParent();
674    
675          int bitpos = 0;      int bitpos = 0;
676          for (int j = 0 ; j < resize.dimension ; j++) {      for (int j = 0 ; j < resize.dimension ; j++) {
677              bitpos += region->pDimensionDefinitions[j].bits;          bitpos += region->pDimensionDefinitions[j].bits;
678          }      }
679    
680        const int stereobitpos =
681            (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
682    
683        // the velocity dimension must be handled differently than all other
684        // dimension types, because
685        // 1. it is currently the only dimension type which allows different zone
686        //    sizes for different cases
687        // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
688        if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
689          int mask =          int mask =
690              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
691          int c = dimregno & mask; // mask away this dimension          int c = maindimregno & mask; // mask away this dimension
692    
693          if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {          if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
694              // the velocity dimension didn't previously have              // the velocity dimension didn't previously have
# Line 381  void DimRegionChooser::update_after_resi Line 711  void DimRegionChooser::update_after_resi
711              }              }
712          }          }
713    
714          gig::DimensionRegion* d = region->pDimensionRegions[c + resize.offset];          int index = c + (resize.zone << bitpos);
715            gig::DimensionRegion* d = region->pDimensionRegions[index];
716          // update both v2 and v3 values          // update both v2 and v3 values
717          d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;          d->DimensionUpperLimits[resize.dimension] = upperLimit;
718          d->VelocityUpperLimit = resize.pos - 1;          d->VelocityUpperLimit = upperLimit;
719            if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
720                gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
721                d->DimensionUpperLimits[resize.dimension] = upperLimit;
722                d->VelocityUpperLimit = upperLimit;
723            }
724    
725            if (modifyalldimregs) {
726                gig::Region* rgn = NULL;
727                for (int key = 0; key < 128; ++key) {
728                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
729                    rgn = instr->GetRegion(key);
730                    if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
731                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
732                    if (!dimdef) continue;
733                    if (dimdef->zones != resize.dimensionDef.zones) continue;
734                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
735                    assert(iDim >= 0 && iDim < rgn->Dimensions);
736    
737                    // the dimension layout might be completely different in this
738                    // region, so we have to recalculate bitpos etc for this region
739                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
740                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
741                    const int selection = resize.zone << bitpos;
742    
743                    // primitive and inefficient loop implementation, however due to
744                    // this circumstance the loop code is much simpler, and its lack
745                    // of runtime efficiency should not be notable in practice
746                    for (int idr = 0; idr < 256; ++idr) {
747                        const int index = (idr & stencil) | selection;
748                        assert(index >= 0 && index < 256);
749                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
750                        if (!dr) continue;
751                        dr->DimensionUpperLimits[iDim] = upperLimit;
752                        d->VelocityUpperLimit = upperLimit;
753                    }
754                }
755            } else if (modifyallregions) { // implies modifyalldimregs is false ...
756                // resolve the precise case we need to modify for all other regions
757                DimensionCase dimCase = dimensionCaseOf(d);
758                // apply the velocity upper limit change to that resolved dim case
759                // of all regions ...
760                gig::Region* rgn = NULL;
761                for (int key = 0; key < 128; ++key) {
762                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
763                    rgn = instr->GetRegion(key);
764                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
765                    if (!dimdef) continue;
766                    if (dimdef->zones != resize.dimensionDef.zones) continue;
767                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
768                    assert(iDim >= 0 && iDim < rgn->Dimensions);
769    
770                    std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
771                    for (int i = 0; i < dimrgns.size(); ++i) {
772                        gig::DimensionRegion* dr = dimrgns[i];
773                        dr->DimensionUpperLimits[iDim] = upperLimit;
774                        dr->VelocityUpperLimit = upperLimit;
775                    }
776                }
777            }
778      } else {      } else {
779          for (int i = 0 ; i < region->DimensionRegions ; ) {          for (int i = 0 ; i < region->DimensionRegions ; ) {
   
780              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
781                  // the dimension didn't previously have custom                  // the dimension didn't previously have custom
782                  // limits, so we have to set default limits for                  // limits, so we have to set default limits for
783                  // all the dimension regions                  // all the dimension regions
                 int bitpos = 0;  
                 for (int j = 0 ; j < resize.dimension ; j++) {  
                     bitpos += region->pDimensionDefinitions[j].bits;  
                 }  
784                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
785    
786                  for (int j = 0 ; j < nbZones ; j++) {                  for (int j = 0 ; j < nbZones ; j++) {
# Line 404  void DimRegionChooser::update_after_resi Line 788  void DimRegionChooser::update_after_resi
788                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
789                  }                  }
790              }              }
791              gig::DimensionRegion* d = region->pDimensionRegions[i + resize.offset];              int index = i + (resize.zone << bitpos);
792              d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              gig::DimensionRegion* d = region->pDimensionRegions[index];
793                d->DimensionUpperLimits[resize.dimension] = upperLimit;
794    #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
795                if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
796                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
797                    d->DimensionUpperLimits[resize.dimension] = upperLimit;
798                }
799    #endif
800              int bitpos = 0;              int bitpos = 0;
801              int j;              int j;
802              for (j = 0 ; j < region->Dimensions ; j++) {              for (j = 0 ; j < region->Dimensions ; j++) {
# Line 420  void DimRegionChooser::update_after_resi Line 810  void DimRegionChooser::update_after_resi
810              if (j == region->Dimensions) break;              if (j == region->Dimensions) break;
811              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
812          }          }
813    
814            if (modifyallregions) { // TODO: this code block could be merged with the similar (and more generalized) code block of the velocity dimension above
815                gig::Region* rgn = NULL;
816                for (int key = 0; key < 128; ++key) {
817                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
818                    rgn = instr->GetRegion(key);
819                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
820                    if (!dimdef) continue;
821                    if (dimdef->zones != resize.dimensionDef.zones) continue;
822                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
823                    assert(iDim >= 0 && iDim < rgn->Dimensions);
824    
825                    // the dimension layout might be completely different in this
826                    // region, so we have to recalculate bitpos etc for this region
827                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
828                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
829                    const int selection = resize.zone << bitpos;
830    
831                    // this loop implementation is less efficient than the above's
832                    // loop implementation (which skips unnecessary dimension regions)
833                    // however this code is much simpler, and its lack of runtime
834                    // efficiency should not be notable in practice
835                    for (int idr = 0; idr < 256; ++idr) {
836                        const int index = (idr & stencil) | selection;
837                        assert(index >= 0 && index < 256);
838                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
839                        if (!dr) continue;
840                        dr->DimensionUpperLimits[iDim] = upperLimit;
841                    }
842                }
843            }
844      }      }
845  }  }
846    
# Line 485  bool DimRegionChooser::on_button_press_e Line 906  bool DimRegionChooser::on_button_press_e
906              }              }
907    
908              int i = dim;              int i = dim;
909              if (dimregno < 0) dimregno = 0;              if (maindimregno < 0) maindimregno = 0;
910              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
911              int c = dimregno & mask; // mask away this dimension              int c = this->maindimregno & mask; // mask away this dimension
912    
913              bool customsplits =              bool customsplits =
914                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
# Line 517  bool DimRegionChooser::on_button_press_e Line 938  bool DimRegionChooser::on_button_press_e
938                     region->pDimensionDefinitions[dim].split_type,                     region->pDimensionDefinitions[dim].split_type,
939                     region->pDimensionDefinitions[dim].zones,                     region->pDimensionDefinitions[dim].zones,
940                     region->pDimensionDefinitions[dim].zone_size);                     region->pDimensionDefinitions[dim].zone_size);
941              dimvalue[region->pDimensionDefinitions[dim].dimension] = z;              this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
942                this->maindimregno = c | (z << bitpos);
943              dimregno = c | (z << bitpos);              this->maindimtype = region->pDimensionDefinitions[dim].dimension;
944    
945                if (multiSelectKeyDown) {
946                    if (dimzones[this->maindimtype].count(z)) {
947                        if (dimzones[this->maindimtype].size() > 1) {
948                            dimzones[this->maindimtype].erase(z);
949                        }
950                    } else {
951                        dimzones[this->maindimtype].insert(z);
952                    }
953                } else {
954                    this->dimzones.clear();
955                    for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
956                         it != this->maindimcase.end(); ++it)
957                    {
958                        this->dimzones[it->first].insert(it->second);
959                    }
960                }
961    
962              focus_line = dim;              focus_line = dim;
963              if (has_focus()) queue_draw();              if (has_focus()) queue_draw();
964              else grab_focus();              else grab_focus();
             dimreg = region->pDimensionRegions[dimregno];  
965              dimregion_selected();              dimregion_selected();
966    
967                if (event->button == 3) {
968                    printf("dimregion right click\n");
969                    popup_menu_inside_dimregion->popup(event->button, event->time);
970                }
971    
972                queue_draw();
973          }          }
974      }      }
975      return true;      return true;
# Line 563  bool DimRegionChooser::on_motion_notify_ Line 1007  bool DimRegionChooser::on_motion_notify_
1007    
1008              resize.pos = k;              resize.pos = k;
1009              update_after_resize();              update_after_resize();
1010              get_window()->invalidate_rect(rect, false);              get_window()->invalidate_rect(rect, false); // not sufficient ...
1011                queue_draw(); // ... so do a complete redraw instead.
1012          }          }
1013      } else {      } else {
1014          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
# Line 599  bool DimRegionChooser::is_in_resize_zone Line 1044  bool DimRegionChooser::is_in_resize_zone
1044          int nbZones = region->pDimensionDefinitions[dim].zones;          int nbZones = region->pDimensionDefinitions[dim].zones;
1045    
1046          int c = 0;          int c = 0;
1047          if (dimregno >= 0) {          if (maindimregno >= 0) {
1048              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
1049              c = dimregno & mask; // mask away this dimension              c = maindimregno & mask; // mask away this dimension
1050          }          }
1051          const bool customsplits =          const bool customsplits =
1052              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
# Line 624  bool DimRegionChooser::is_in_resize_zone Line 1069  bool DimRegionChooser::is_in_resize_zone
1069                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
1070                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
1071                      resize.dimension = dim;                      resize.dimension = dim;
1072                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
1073                        resize.zone = iZone;
1074                      resize.pos = limit;                      resize.pos = limit;
1075                      resize.min = prev_limit;                      resize.min = prev_limit;
1076    
1077                      int dr = (dimregno >> bitpos) &                      int dr = (maindimregno >> bitpos) &
1078                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);
1079                      resize.selected = dr == iZone ? resize.left :                      resize.selected = dr == iZone ? resize.left :
1080                          dr == iZone + 1 ? resize.right : resize.none;                          dr == iZone + 1 ? resize.right : resize.none;
# Line 665  sigc::signal<void>& DimRegionChooser::si Line 1111  sigc::signal<void>& DimRegionChooser::si
1111    
1112  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
1113  {  {
1114      // 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
1115      // fokus.      // to set focus
1116      if (direction == Gtk::DIR_TAB_FORWARD ||      if (direction == Gtk::DIR_TAB_FORWARD ||
1117          direction == Gtk::DIR_DOWN) {          direction == Gtk::DIR_DOWN) {
1118          if (!has_focus()) {          if (!has_focus()) {
# Line 698  bool DimRegionChooser::on_focus(Gtk::Dir Line 1144  bool DimRegionChooser::on_focus(Gtk::Dir
1144              }              }
1145          }          }
1146      } else if (!has_focus()) {      } else if (!has_focus()) {
1147          // TODO: kolla att focus_line finns!          // TODO: check that focus_line exists
1148          grab_focus();          grab_focus();
1149          return true;          return true;
1150      } else {      } else {
1151          // TODO: öka eller minska värde!          // TODO: increase or decrease value
1152        }
1153        return false;
1154    }
1155    
1156    void DimRegionChooser::split_dimension_zone() {    
1157        printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1158        try {
1159            if (!modifyallregions) {
1160                region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1161            } else {
1162                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1163                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1164                assert(pMaindimdef != NULL);
1165                // retain structure by value since the original region will be
1166                // modified in the loop below as well
1167                gig::dimension_def_t maindimdef = *pMaindimdef;
1168                std::vector<gig::Region*> ignoredAll;
1169                std::vector<gig::Region*> ignoredMinor;
1170                std::vector<gig::Region*> ignoredCritical;
1171                gig::Region* rgn = NULL;
1172                for (int key = 0; key < 128; ++key) {
1173                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1174                    rgn = instr->GetRegion(key);
1175    
1176                    // ignore all regions which do not exactly match the dimension
1177                    // layout of the selected region where this operation was emitted
1178                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1179                    if (!dimdef) {
1180                        ignoredAll.push_back(rgn);
1181                        ignoredMinor.push_back(rgn);
1182                        continue;
1183                    }
1184                    if (dimdef->zones != maindimdef.zones) {
1185                        ignoredAll.push_back(rgn);
1186                        ignoredCritical.push_back(rgn);
1187                        continue;
1188                    }
1189    
1190                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1191                }
1192                if (!ignoredAll.empty()) {
1193                    Glib::ustring txt;
1194                    if (ignoredCritical.empty())
1195                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1196                    else if (ignoredMinor.empty())
1197                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1198                    else
1199                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1200                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1201                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1202                    Gtk::MessageDialog msg(txt, false, type);
1203                    msg.run();
1204                }
1205            }
1206        } catch (RIFF::Exception e) {
1207            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1208            msg.run();
1209        } catch (...) {
1210            Glib::ustring txt = _("An unknown exception occurred!");
1211            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1212            msg.run();
1213        }
1214        refresh_all();
1215    }
1216    
1217    void DimRegionChooser::delete_dimension_zone() {
1218        printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1219        try {
1220            if (!modifyallregions) {
1221                region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1222            } else {
1223                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1224                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1225                assert(pMaindimdef != NULL);
1226                // retain structure by value since the original region will be
1227                // modified in the loop below as well
1228                gig::dimension_def_t maindimdef = *pMaindimdef;
1229                std::vector<gig::Region*> ignoredAll;
1230                std::vector<gig::Region*> ignoredMinor;
1231                std::vector<gig::Region*> ignoredCritical;
1232                gig::Region* rgn = NULL;
1233                for (int key = 0; key < 128; ++key) {
1234                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1235                    rgn = instr->GetRegion(key);
1236    
1237                    // ignore all regions which do not exactly match the dimension
1238                    // layout of the selected region where this operation was emitted
1239                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1240                    if (!dimdef) {
1241                        ignoredAll.push_back(rgn);
1242                        ignoredMinor.push_back(rgn);
1243                        continue;
1244                    }
1245                    if (dimdef->zones != maindimdef.zones) {
1246                        ignoredAll.push_back(rgn);
1247                        ignoredCritical.push_back(rgn);
1248                        continue;
1249                    }
1250    
1251                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1252                }
1253                if (!ignoredAll.empty()) {
1254                    Glib::ustring txt;
1255                    if (ignoredCritical.empty())
1256                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1257                    else if (ignoredMinor.empty())
1258                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1259                    else
1260                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1261                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1262                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1263                    Gtk::MessageDialog msg(txt, false, type);
1264                    msg.run();
1265                }
1266            }
1267        } catch (RIFF::Exception e) {
1268            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1269            msg.run();
1270        } catch (...) {
1271            Glib::ustring txt = _("An unknown exception occurred!");
1272            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1273            msg.run();
1274      }      }
1275        refresh_all();
1276    }
1277    
1278    // Cmd key on Mac, Ctrl key on all other OSs
1279    static const guint primaryKeyL =
1280        #if defined(__APPLE__)
1281        GDK_KEY_Meta_L;
1282        #else
1283        GDK_KEY_Control_L;
1284        #endif
1285    
1286    static const guint primaryKeyR =
1287        #if defined(__APPLE__)
1288        GDK_KEY_Meta_R;
1289        #else
1290        GDK_KEY_Control_R;
1291        #endif
1292    
1293    bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1294        //printf("key down 0x%x\n", key->keyval);
1295        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1296            multiSelectKeyDown = true;
1297        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1298            primaryKeyDown = true;
1299        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1300            shiftKeyDown = true;
1301    
1302        //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
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        return false;
1312    }
1313    
1314    bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1315        //printf("key up 0x%x\n", key->keyval);
1316        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1317            multiSelectKeyDown = false;
1318        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1319            primaryKeyDown = false;
1320        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1321            shiftKeyDown = false;
1322    
1323        if (!has_focus()) return false;
1324    
1325        // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow
1326        // (which is supposed to switch between regions)
1327        if (primaryKeyDown) return false;
1328    
1329        // avoid conflict with Alt+Shift+Left and Alt+Shift+Right accelerators on
1330        // mainwindow
1331        if (shiftKeyDown) return false;
1332    
1333        if (key->keyval == GDK_KEY_Left)
1334            select_prev_dimzone();
1335        if (key->keyval == GDK_KEY_Right)
1336            select_next_dimzone();
1337        if (key->keyval == GDK_KEY_Up)
1338            select_prev_dimension();
1339        if (key->keyval == GDK_KEY_Down)
1340            select_next_dimension();
1341    
1342        return false;
1343    }
1344    
1345    void DimRegionChooser::resetSelectedZones() {
1346        this->dimzones.clear();
1347        if (!region) {
1348            queue_draw(); // redraw required parts
1349            return;
1350        }
1351        if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1352            queue_draw(); // redraw required parts
1353            return;
1354        }
1355        if (!region->pDimensionRegions[maindimregno]) {
1356            queue_draw(); // redraw required parts
1357            return;
1358        }
1359        gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1360    
1361        bool isValidZone;
1362        this->maindimcase = dimensionCaseOf(dimrgn);
1363    
1364        for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1365             it != this->maindimcase.end(); ++it)
1366        {
1367            this->dimzones[it->first].insert(it->second);
1368        }
1369    
1370        // redraw required parts
1371        queue_draw();
1372    }
1373    
1374    bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1375        if (!region) return false; //.selection failed
1376    
1377        for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1378            if (region->pDimensionRegions[dr] == dimrgn) {
1379                // reset dim region zone selection to the requested specific dim region case
1380                maindimregno = dr;
1381                resetSelectedZones();
1382    
1383                // emit signal that dimregion selection has changed, for external entities
1384                dimregion_selected();
1385    
1386                return true; // selection success
1387            }
1388        }
1389    
1390        return false; //.selection failed
1391    }
1392    
1393    void DimRegionChooser::select_next_dimzone(bool add) {
1394        select_dimzone_by_dir(+1, add);
1395    }
1396    
1397    void DimRegionChooser::select_prev_dimzone(bool add) {
1398        select_dimzone_by_dir(-1, add);
1399    }
1400    
1401    void DimRegionChooser::select_dimzone_by_dir(int dir, bool add) {
1402        if (!region) return;
1403        if (!region->Dimensions) return;
1404        if (focus_line < 0) focus_line = 0;
1405        if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1406    
1407        maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1408        if (maindimtype == gig::dimension_none) {
1409            printf("maindimtype -> none\n");
1410            return;
1411        }
1412    
1413        if (maindimcase.empty()) {
1414            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1415            if (maindimcase.empty()) {
1416                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1417                return;
1418            }
1419        }
1420    
1421        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1422        if (z < 0) z = 0;
1423        if (z >= region->pDimensionDefinitions[focus_line].zones)
1424            z = region->pDimensionDefinitions[focus_line].zones - 1;
1425    
1426        maindimcase[maindimtype] = z;
1427    
1428        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1429        if (!dr) {
1430            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1431            return;
1432        }
1433    
1434        maindimregno = getDimensionRegionIndex(dr);
1435    
1436        if (!add) {
1437            // reset selected dimregion zones
1438            dimzones.clear();
1439        }
1440        for (DimensionCase::const_iterator it = maindimcase.begin();
1441             it != maindimcase.end(); ++it)
1442        {
1443            dimzones[it->first].insert(it->second);
1444        }
1445    
1446        dimregion_selected();
1447    
1448        // disabled: would overwrite dimregno with wrong value
1449        //refresh_all();
1450        // so requesting just a raw repaint instead:
1451        queue_draw();
1452    }
1453    
1454    void DimRegionChooser::select_next_dimension() {
1455        if (!region) return;
1456        focus_line++;
1457        if (focus_line >= region->Dimensions)
1458            focus_line = region->Dimensions - 1;
1459        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1460        queue_draw();
1461    }
1462    
1463    void DimRegionChooser::select_prev_dimension() {
1464        if (!region) return;
1465        focus_line--;
1466        if (focus_line < 0)
1467            focus_line = 0;
1468        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1469        queue_draw();
1470    }
1471    
1472    gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1473        if (!region) return NULL;
1474        return region->pDimensionRegions[maindimregno];
1475  }  }

Legend:
Removed from v.2246  
changed lines
  Added in v.3286

  ViewVC Help
Powered by ViewVC