/[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 2462 by schoenebeck, Wed Sep 4 20:23:05 2013 UTC revision 3134 by schoenebeck, Fri Apr 28 12:41:12 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 <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>
27    #include <glibmm/ustring.h>
28    #include <gtkmm/messagedialog.h>
29    #include <assert.h>
30    
31  #include "global.h"  #include "global.h"
32    #include "gfx/builtinpix.h"
33    
34  DimRegionChooser::DimRegionChooser() :  //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
35      red("#8070ff"),  static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
36        DimensionCase dimCase;
37        if (!dr) {
38            *isValidZone = false;
39            return dimCase;
40        }
41    
42        gig::Region* rgn = (gig::Region*) dr->GetParent();
43    
44        // find the dimension region index of the passed dimension region
45        int drIndex;
46        for (drIndex = 0; drIndex < 256; ++drIndex)
47            if (rgn->pDimensionRegions[drIndex] == dr)
48                break;
49    
50        // not found in region, something's horribly wrong
51        if (drIndex == 256) {
52            fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
53            *isValidZone = false;
54            return DimensionCase();
55        }
56    
57        for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
58            const int bits = rgn->pDimensionDefinitions[d].bits;
59            dimCase[rgn->pDimensionDefinitions[d].dimension] =
60                (drIndex >> baseBits) & ((1 << bits) - 1);
61            baseBits += bits;
62            // there are also DimensionRegion objects of unused zones, skip them
63            if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
64                *isValidZone = false;
65                return DimensionCase();
66            }
67        }
68    
69        *isValidZone = true;
70        return dimCase;
71    }
72    
73    DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
74        red("#ff476e"),
75        blue("#4796ff"),
76      black("black"),      black("black"),
77      white("white")      white("white")
78  {  {
79        // make sure blue hatched pattern pixmap is loaded
80        loadBuiltInPix();
81    
82        // create blue hatched pattern
83        {
84            const int width = blueHatchedPattern->get_width();
85            const int height = blueHatchedPattern->get_height();
86            const int stride = blueHatchedPattern->get_rowstride();
87    
88            // manually convert from RGBA to ARGB
89            this->blueHatchedPatternARGB = blueHatchedPattern->copy();
90            const int pixelSize = stride / width;
91            const int totalPixels = width * height;
92            assert(pixelSize == 4);
93            unsigned char* ptr = this->blueHatchedPatternARGB->get_pixels();
94            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
95                const unsigned char r = ptr[0];
96                const unsigned char g = ptr[1];
97                const unsigned char b = ptr[2];
98                const unsigned char a = ptr[3];
99                ptr[0] = b;
100                ptr[1] = g;
101                ptr[2] = r;
102                ptr[3] = a;
103            }
104    
105            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
106                this->blueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
107            );
108            this->blueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
109            this->blueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
110        }
111    
112      instrument = 0;      instrument = 0;
113      region = 0;      region = 0;
114      dimregno = -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;
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();
130        actionSplitDimZone = Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
131        actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
132        actionGroup->add(
133            actionSplitDimZone,
134            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(
139            actionDeleteDimZone,
140            sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
141        );
142    
143        uiManager = Gtk::UIManager::create();
144        uiManager->insert_action_group(actionGroup);
145        Glib::ustring ui_info =
146            "<ui>"
147            "  <popup name='PopupMenuInsideDimRegion'>"
148            "    <menuitem action='SplitDimZone'/>"
149            "    <menuitem action='DeleteDimZone'/>"
150            "  </popup>"
151    //         "  <popup name='PopupMenuOutsideDimRegion'>"
152    //         "    <menuitem action='Add'/>"
153    //         "  </popup>"
154            "</ui>";
155        uiManager->add_ui_from_string(ui_info);
156    
157        popup_menu_inside_dimregion = dynamic_cast<Gtk::Menu*>(
158            uiManager->get_widget("/PopupMenuInsideDimRegion"));
159    //     popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(
160    //         uiManager->get_widget("/PopupMenuOutsideDimRegion"));
161    
162      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
163                 Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_HINT_MASK);
164    
     for (int i = 0 ; i < 256 ; i++) dimvalue[i] = 0;  
165      labels_changed = true;      labels_changed = true;
166    
167        set_tooltip_text(_(
168            "Right click here for options on altering dimension zones. Press and "
169            "hold CTRL key for selecting multiple dimension zones simultaniously."
170        ));
171        
172        window.signal_key_press_event().connect(
173            sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)
174        );
175        window.signal_key_release_event().connect(
176            sigc::mem_fun(*this, &DimRegionChooser::onKeyReleased)
177        );
178  }  }
179    
180  DimRegionChooser::~DimRegionChooser()  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 58  bool DimRegionChooser::on_expose_event(G Line 206  bool DimRegionChooser::on_expose_event(G
206    
207      const Cairo::RefPtr<Cairo::Context>& cr =      const Cairo::RefPtr<Cairo::Context>& cr =
208          get_window()->create_cairo_context();          get_window()->create_cairo_context();
 #if 0  
 }  
 #endif  
209  #else  #else
210  bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)  bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
211  {  {
# Line 139  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 176  bool DimRegionChooser::on_draw(const Cai Line 331  bool DimRegionChooser::on_draw(const Cai
331      for (int i = 0 ; i < region->Dimensions ; i++) {      for (int i = 0 ; i < region->Dimensions ; i++) {
332          int nbZones = region->pDimensionDefinitions[i].zones;          int nbZones = region->pDimensionDefinitions[i].zones;
333          if (nbZones) {          if (nbZones) {
334                const gig::dimension_t dimension = region->pDimensionDefinitions[i].dimension;
335    
336              if (y >= clipy2) break;              if (y >= clipy2) break;
337              if (y + h > clipy1) {              if (y + h > clipy1) {
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 206  bool DimRegionChooser::on_draw(const Cai Line 363  bool DimRegionChooser::on_draw(const Cai
363                  cr->fill();                  cr->fill();
364    
365                  int c = 0;                  int c = 0;
366                  if (dimregno >= 0) {                  if (maindimregno >= 0) {
367                      int mask =                      int mask =
368                          ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<                          ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
369                            bitpos);                            bitpos);
370                      c = dimregno & mask; // mask away this dimension                      c = maindimregno & mask; // mask away this dimension
371                  }                  }
372                  bool customsplits =                  bool customsplits =
373                      ((region->pDimensionDefinitions[i].split_type ==                      ((region->pDimensionDefinitions[i].split_type ==
# Line 220  bool DimRegionChooser::on_draw(const Cai Line 377  bool DimRegionChooser::on_draw(const Cai
377                        gig::dimension_velocity &&                        gig::dimension_velocity &&
378                        region->pDimensionRegions[c]->VelocityUpperLimit));                        region->pDimensionRegions[c]->VelocityUpperLimit));
379    
380                  // draw dimension's zone borders                  // draw dimension zones
381                  Gdk::Cairo::set_source_rgba(cr, black);                  Gdk::Cairo::set_source_rgba(cr, black);
382                  if (customsplits) {                  if (customsplits) {
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;
386                        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
390                          gig::DimensionRegion* d =                          gig::DimensionRegion* d =
391                              region->pDimensionRegions[c + (j << bitpos)];                              region->pDimensionRegions[c + (j << bitpos)];
392                          int upperLimit = d->DimensionUpperLimits[i];                          int upperLimit = d->DimensionUpperLimits[i];
# Line 236  bool DimRegionChooser::on_draw(const Cai Line 396  bool DimRegionChooser::on_draw(const Cai
396                              label_width;                              label_width;
397                          if (x >= clipx2) break;                          if (x >= clipx2) break;
398                          if (x < clipx1) continue;                          if (x < clipx1) continue;
399                            Gdk::Cairo::set_source_rgba(cr, black);
400                          cr->move_to(x + 0.5, y + 1);                          cr->move_to(x + 0.5, y + 1);
401                          cr->line_to(x + 0.5, y + h - 1);                          cr->line_to(x + 0.5, y + h - 1);
402                            cr->stroke();
403    
404                            // draw fill for zone
405                            bool isSelectedZone = this->dimzones[dimension].count(j);
406                            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);
417                            cr->fill();
418    
419                            // draw text showing the beginning of the dimension zone
420                            // as numeric value to the user
421                            {
422                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
423                                layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
424                                Gdk::Cairo::set_source_rgba(cr, black);
425                                // get the text dimensions
426                                int text_width, text_height;
427                                layout->get_pixel_size(text_width, text_height);
428                                // move text to the left end of the dimension zone
429                                cr->move_to(prevX + 3, y + (h - text_height) / 2);
430    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
431                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
432    #else
433                                layout->show_in_cairo_context(cr);
434    #endif
435                            }
436                            // draw text showing the end of the dimension zone
437                            // as numeric value to the user
438                            {
439                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
440                                layout->set_text(Glib::Ascii::dtostr(upperLimit));
441                                Gdk::Cairo::set_source_rgba(cr, black);
442                                // get the text dimensions
443                                int text_width, text_height;
444                                layout->get_pixel_size(text_width, text_height);
445                                // move text to the left end of the dimension zone
446                                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
448                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
449    #else
450                                layout->show_in_cairo_context(cr);
451    #endif
452                            }
453    
454                            prevX = x;
455                            prevUpperLimit = upperLimit;
456                      }                      }
457                  } else {                  } else {
458                        int prevX = 0;
459                      for (int j = 0 ; j <= nbZones ; j++) {                      for (int j = 0 ; j <= nbZones ; j++) {
460                            // draw dimension zone's borders for normal splits
461                          int x = int((w - label_width - 1) * j /                          int x = int((w - label_width - 1) * j /
462                                      double(nbZones) + 0.5) + label_width;                                      double(nbZones) + 0.5) + label_width;
463                          if (x >= clipx2) break;                          if (x >= clipx2) break;
464                          if (x < clipx1) continue;                          if (x < clipx1) continue;
465                            Gdk::Cairo::set_source_rgba(cr, black);
466                          cr->move_to(x + 0.5, y + 1);                          cr->move_to(x + 0.5, y + 1);
467                          cr->line_to(x + 0.5, y + h - 1);                          cr->line_to(x + 0.5, y + h - 1);
468                      }                          cr->stroke();
                 }  
                 cr->stroke();  
469    
470                  // draw fill for currently selected zone                          if (j != 0) {
471                  if (dimregno >= 0) {                              // draw fill for zone
472                      Gdk::Cairo::set_source_rgba(cr, red);                              bool isSelectedZone = this->dimzones[dimension].count(j-1);
473                      int dr = (dimregno >> bitpos) &                              bool isMainSelection =
474                          ((1 << region->pDimensionDefinitions[i].bits) - 1);                                  this->maindimcase.find(dimension) != this->maindimcase.end() &&
475                                                        this->maindimcase[dimension] == (j-1);
476                      int x1 = -1, x2 = -1;                              if (isMainSelection)
477                      if (customsplits) {                                  Gdk::Cairo::set_source_rgba(cr, blue);
478                          x1 = label_width;                              else if (isSelectedZone)
479                          for (int j = 0 ; j < nbZones && x1 + 1 < clipx2 ; j++) {                                  cr->set_source(blueHatchedSurfacePattern);
480                              gig::DimensionRegion* d =                              else
481                                  region->pDimensionRegions[c + (j << bitpos)];                                  Gdk::Cairo::set_source_rgba(cr, white);
482                              int upperLimit = d->DimensionUpperLimits[i];                              cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
                             if (!upperLimit) {  
                                 upperLimit = d->VelocityUpperLimit;  
                             }  
                             int v = upperLimit + 1;  
                             x2 = int((w - label_width - 1) * v / 128.0 +  
                                      0.5) + label_width;  
                             if (j == dr && x1 < x2) {  
                                 cr->rectangle(x1 + 1, y + 1,  
                                               (x2 - x1) - 1, h - 2);  
                                 cr->fill();  
                                 break;  
                             }  
                             x1 = x2;  
                         }  
                     } else {  
                         if (dr < nbZones) {  
                             x1 = int((w - label_width - 1) * dr /  
                                      double(nbZones) + 0.5);  
                             x2 = int((w - label_width - 1) * (dr + 1) /  
                                      double(nbZones) + 0.5);  
                             cr->rectangle(label_width + x1 + 1, y + 1,  
                                           (x2 - x1) - 1, h - 2);  
483                              cr->fill();                              cr->fill();
                         }  
                     }  
484    
485                      // draw text showing the beginning of the dimension zone                              // draw text showing the beginning of the dimension zone
486                      // as numeric value to the user                              // as numeric value to the user
487                      if (x1 >= 0) {                              {
488                          Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
489                          int v = roundf(float(x1 - label_width) / float(w - label_width) * 127.f);                                  layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
490                          if (dr > 0) v++;                                  Gdk::Cairo::set_source_rgba(cr, black);
491                          layout->set_text(Glib::Ascii::dtostr(v));                                  // get the text dimensions
492                          Gdk::Cairo::set_source_rgba(cr, black);                                  int text_width, text_height;
493                          Pango::Rectangle rect = layout->get_logical_extents();                                  layout->get_pixel_size(text_width, text_height);
494                                                            // move text to the left end of the dimension zone
495                          int text_width, text_height;                                  cr->move_to(prevX + 3, y + (h - text_height) / 2);
                         // get the text dimensions  
                         layout->get_pixel_size(text_width, text_height);  
                         // move text to the right end of the dimension zone  
                         cr->move_to(x1 + 1, y + 1);  
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
499                          layout->show_in_cairo_context(cr);                                  layout->show_in_cairo_context(cr);
500  #endif  #endif
501                      }                              }
502                      // draw text showing the end of the dimension zone                              // draw text showing the end of the dimension zone
503                      // as numeric value to the user                              // as numeric value to the user
504                      if (x2 >= 0) {                              {
505                          Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
506                          const int v = roundf(float(x2 - label_width) / float(w - label_width) * 127.f);                                  layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
507                          layout->set_text(Glib::Ascii::dtostr(v));                                  Gdk::Cairo::set_source_rgba(cr, black);
508                          Gdk::Cairo::set_source_rgba(cr, black);                                  // get the text dimensions
509                          Pango::Rectangle rect = layout->get_logical_extents();                                  int text_width, text_height;
510                                                            layout->get_pixel_size(text_width, text_height);
511                          int text_width, text_height;                                  // move text to the left end of the dimension zone
512                          // get the text dimensions                                  cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
                         layout->get_pixel_size(text_width, text_height);  
                         // move text to the right end of the dimension zone  
                         cr->move_to(x2 - text_width - 1, y + 1);  
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
516                          layout->show_in_cairo_context(cr);                                  layout->show_in_cairo_context(cr);
517  #endif  #endif
518                      }                              }
519                            }
520                            prevX = x;
521                        }      
522                  }                  }
523              }              }
   
524              y += h;              y += h;
525          }          }
526          bitpos += region->pDimensionDefinitions[i].bits;          bitpos += region->pDimensionDefinitions[i].bits;
# Line 345  bool DimRegionChooser::on_draw(const Cai Line 532  bool DimRegionChooser::on_draw(const Cai
532  void DimRegionChooser::set_region(gig::Region* region)  void DimRegionChooser::set_region(gig::Region* region)
533  {  {
534      this->region = region;      this->region = region;
535      dimregno = 0;      maindimregno = 0;
536      nbDimensions = 0;      nbDimensions = 0;
537      if (region) {      if (region) {
538          int bitcount = 0;          int bitcount = 0;
# Line 353  void DimRegionChooser::set_region(gig::R Line 540  void DimRegionChooser::set_region(gig::R
540              if (region->pDimensionDefinitions[dim].bits == 0) continue;              if (region->pDimensionDefinitions[dim].bits == 0) continue;
541              nbDimensions++;              nbDimensions++;
542    
543              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
544                               region->pDimensionDefinitions[dim].zones - 1);                               region->pDimensionDefinitions[dim].zones - 1);
545              dimregno |= (z << bitcount);              maindimregno |= (z << bitcount);
546              bitcount += region->pDimensionDefinitions[dim].bits;              bitcount += region->pDimensionDefinitions[dim].bits;
547          }          }
         dimreg = region->pDimensionRegions[dimregno];  
     } else {  
         dimreg = 0;  
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();
554        queue_draw();
555  }  }
556    
557    void DimRegionChooser::refresh_all() {
558        set_region(region);
559    }
560    
561  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
562                                        std::set<gig::DimensionRegion*>& dimregs) const                                        std::set<gig::DimensionRegion*>& dimregs) const
563  {  {
564      int dimregno = 0;      for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
565      int bitcount = 0;          gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
566      int stereo_bit = 0;          if (!dimRgn) continue;
567      for (int dim = 0 ; dim < region->Dimensions ; dim++) {          bool isValidZone;
568          if (region->pDimensionDefinitions[dim].bits == 0) continue;          std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
569          if (stereo &&          if (!isValidZone) continue;
570              region->pDimensionDefinitions[dim].dimension == gig::dimension_samplechannel) {          for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
571              stereo_bit = (1 << bitcount);               it != dimCase.end(); ++it)
572          } else {          {
573              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
574                               region->pDimensionDefinitions[dim].zones - 1);  
575              dimregno |= (z << bitcount);              std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
576                    this->dimzones.find(it->first);
577                if (itSelectedDimension != this->dimzones.end() &&
578                    itSelectedDimension->second.count(it->second)) continue; // is selected
579    
580                goto notSelected;
581          }          }
582          bitcount += region->pDimensionDefinitions[dim].bits;  
583            dimregs.insert(dimRgn);
584    
585            notSelected:
586            ;
587      }      }
     dimregs.insert(region->pDimensionRegions[dimregno]);  
     if (stereo_bit) dimregs.insert(region->pDimensionRegions[dimregno | stereo_bit]);  
588  }  }
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 = dimregno & mask; // mask away this dimension          int c = maindimregno & mask; // mask away this dimension
612    
613          if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {          if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
614              // the velocity dimension didn't previously have              // the velocity dimension didn't previously have
# Line 425  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 448  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 464  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 529  bool DimRegionChooser::on_button_press_e Line 826  bool DimRegionChooser::on_button_press_e
826              }              }
827    
828              int i = dim;              int i = dim;
829              if (dimregno < 0) dimregno = 0;              if (maindimregno < 0) maindimregno = 0;
830              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
831              int c = dimregno & mask; // mask away this dimension              int c = this->maindimregno & mask; // mask away this dimension
832    
833              bool customsplits =              bool customsplits =
834                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
# Line 561  bool DimRegionChooser::on_button_press_e Line 858  bool DimRegionChooser::on_button_press_e
858                     region->pDimensionDefinitions[dim].split_type,                     region->pDimensionDefinitions[dim].split_type,
859                     region->pDimensionDefinitions[dim].zones,                     region->pDimensionDefinitions[dim].zones,
860                     region->pDimensionDefinitions[dim].zone_size);                     region->pDimensionDefinitions[dim].zone_size);
861              dimvalue[region->pDimensionDefinitions[dim].dimension] = z;              this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
862                this->maindimregno = c | (z << bitpos);
863              dimregno = c | (z << bitpos);              this->maindimtype = region->pDimensionDefinitions[dim].dimension;
864    
865                if (multiSelectKeyDown) {
866                    if (dimzones[this->maindimtype].count(z)) {
867                        if (dimzones[this->maindimtype].size() > 1) {
868                            dimzones[this->maindimtype].erase(z);
869                        }
870                    } else {
871                        dimzones[this->maindimtype].insert(z);
872                    }
873                } else {
874                    this->dimzones.clear();
875                    for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
876                         it != this->maindimcase.end(); ++it)
877                    {
878                        this->dimzones[it->first].insert(it->second);
879                    }
880                }
881    
882              focus_line = dim;              focus_line = dim;
883              if (has_focus()) queue_draw();              if (has_focus()) queue_draw();
884              else grab_focus();              else grab_focus();
             dimreg = region->pDimensionRegions[dimregno];  
885              dimregion_selected();              dimregion_selected();
886    
887                if (event->button == 3) {
888                    printf("dimregion right click\n");
889                    popup_menu_inside_dimregion->popup(event->button, event->time);
890                }
891    
892                queue_draw();
893          }          }
894      }      }
895      return true;      return true;
# Line 607  bool DimRegionChooser::on_motion_notify_ Line 927  bool DimRegionChooser::on_motion_notify_
927    
928              resize.pos = k;              resize.pos = k;
929              update_after_resize();              update_after_resize();
930              get_window()->invalidate_rect(rect, false);              get_window()->invalidate_rect(rect, false); // not sufficient ...
931                queue_draw(); // ... so do a complete redraw instead.
932          }          }
933      } else {      } else {
934          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
# Line 643  bool DimRegionChooser::is_in_resize_zone Line 964  bool DimRegionChooser::is_in_resize_zone
964          int nbZones = region->pDimensionDefinitions[dim].zones;          int nbZones = region->pDimensionDefinitions[dim].zones;
965    
966          int c = 0;          int c = 0;
967          if (dimregno >= 0) {          if (maindimregno >= 0) {
968              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
969              c = dimregno & mask; // mask away this dimension              c = maindimregno & mask; // mask away this dimension
970          }          }
971          const bool customsplits =          const bool customsplits =
972              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
# Line 668  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    
997                      int dr = (dimregno >> bitpos) &                      int dr = (maindimregno >> bitpos) &
998                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);
999                      resize.selected = dr == iZone ? resize.left :                      resize.selected = dr == iZone ? resize.left :
1000                          dr == iZone + 1 ? resize.right : resize.none;                          dr == iZone + 1 ? resize.right : resize.none;
# Line 709  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 742  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() {    
1077        printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1078        try {
1079            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) {
1127            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1128            msg.run();
1129        } catch (...) {
1130            Glib::ustring txt = _("An unknown exception occurred!");
1131            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1132            msg.run();
1133        }
1134        refresh_all();
1135    }
1136    
1137    void DimRegionChooser::delete_dimension_zone() {
1138        printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1139        try {
1140            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) {
1188            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1189            msg.run();
1190        } catch (...) {
1191            Glib::ustring txt = _("An unknown exception occurred!");
1192            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1193            msg.run();
1194        }
1195        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) {
1214        //printf("key down 0x%x\n", key->keyval);
1215        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1216            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) {
1235        //printf("key up 0x%x\n", key->keyval);
1236        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1237            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 {
1393        if (!region) return NULL;
1394        return region->pDimensionRegions[maindimregno];
1395  }  }

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

  ViewVC Help
Powered by ViewVC