/[svn]/gigedit/trunk/src/gigedit/dimregionchooser.cpp
ViewVC logotype

Diff of /gigedit/trunk/src/gigedit/dimregionchooser.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2626 by schoenebeck, Thu Jun 12 15:12:00 2014 UTC revision 3307 by schoenebeck, Tue Jul 11 23:06:38 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2014 Andreas Persson   * Copyright (C) 2006-2017 Andreas Persson
3   *   *
4   * This program is free software; you can redistribute it and/or   * This program is free software; you can redistribute it and/or
5   * modify it under the terms of the GNU General Public License as   * modify it under the terms of the GNU General Public License as
# Line 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
20    #include "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>  #include <glibmm/stringutils.h>
28  #include <gtkmm/stock.h>  #include <gtkmm/stock.h>
29  #include <glibmm/ustring.h>  #include <glibmm/ustring.h>
30  #include <gtkmm/messagedialog.h>  #include <gtkmm/messagedialog.h>
31    #include <assert.h>
32    
33  #include "global.h"  #include "gfx/builtinpix.h"
   
 // taken from gdk/gdkkeysyms.h  
 // (define on demand, to avoid unnecessary dev lib package build dependency)  
 #ifndef GDK_KEY_Control_L  
 # define GDK_KEY_Control_L 0xffe3  
 #endif  
 #ifndef GDK_KEY_Control_R  
 # define GDK_KEY_Control_R 0xffe4  
 #endif  
34    
35  static std::map<gig::dimension_t,int> caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {  //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
36      std::map<gig::dimension_t,int> dimCase;  static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
37        DimensionCase dimCase;
38      if (!dr) {      if (!dr) {
39          *isValidZone = false;          *isValidZone = false;
40          return dimCase;          return dimCase;
# Line 56  static std::map<gig::dimension_t,int> ca Line 52  static std::map<gig::dimension_t,int> ca
52      if (drIndex == 256) {      if (drIndex == 256) {
53          fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");          fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
54          *isValidZone = false;          *isValidZone = false;
55          return std::map<gig::dimension_t,int>();          return DimensionCase();
56      }      }
57    
58      for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {      for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
# Line 67  static std::map<gig::dimension_t,int> ca Line 63  static std::map<gig::dimension_t,int> ca
63          // there are also DimensionRegion objects of unused zones, skip them          // there are also DimensionRegion objects of unused zones, skip them
64          if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {          if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
65              *isValidZone = false;              *isValidZone = false;
66              return std::map<gig::dimension_t,int>();              return DimensionCase();
67          }          }
68      }      }
69    
# Line 76  static std::map<gig::dimension_t,int> ca Line 72  static std::map<gig::dimension_t,int> ca
72  }  }
73    
74  DimRegionChooser::DimRegionChooser(Gtk::Window& window) :  DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
75      red("#8070ff"),      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      maindimregno = -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;      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();      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(      actionGroup->add(
194          Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone")),          actionSplitDimZone,
195          sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)          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(      actionGroup->add(
200          Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone")),          actionDeleteDimZone,
201          sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)          sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
202      );      );
203    
# Line 141  DimRegionChooser::~DimRegionChooser() Line 242  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    void DimRegionChooser::drawIconsFor(
268        gig::dimension_t dimension, uint zone,
269        const Cairo::RefPtr<Cairo::Context>& cr,
270        int x, int y, int w, int h)
271    {
272        DimensionCase dimCase;
273        dimCase[dimension] = zone;
274    
275        std::vector<gig::DimensionRegion*> dimregs =
276            dimensionRegionsMatching(dimCase, region, true);
277    
278        if (dimregs.empty()) return;
279    
280        int iSampleRefs = 0;
281        int iLoops = 0;
282    
283        for (uint i = 0; i < dimregs.size(); ++i) {
284            if (dimregs[i]->pSample) iSampleRefs++;
285            if (dimregs[i]->SampleLoops) iLoops++;
286        }
287    
288        bool bShowLoopSymbol = (iLoops > 0);
289        bool bShowSampleRefSymbol = (iSampleRefs < dimregs.size());
290    
291        if (bShowLoopSymbol || bShowSampleRefSymbol) {
292            const int margin = 1;
293    
294            cr->save();
295            cr->set_line_width(1);
296            cr->rectangle(x, y + margin, w, h - 2*margin);
297            cr->clip();
298            if (bShowSampleRefSymbol) {
299                const int wPic = 8;
300                const int hPic = 8;
301                Gdk::Cairo::set_source_pixbuf(
302                    cr, (iSampleRefs) ? yellowDot : redDot,
303                    x + (w-wPic)/2.f,
304                    y + (
305                        (bShowLoopSymbol) ? margin : (h-hPic)/2.f
306                    )
307                );
308                cr->paint();
309            }
310            if (bShowLoopSymbol) {
311                const int wPic = 12;
312                const int hPic = 14;
313                Gdk::Cairo::set_source_pixbuf(
314                    cr, (iLoops == dimregs.size()) ? blackLoop : grayLoop,
315                    x + (w-wPic)/2.f,
316                    y + (
317                        (bShowSampleRefSymbol) ? h - hPic - margin : (h-hPic)/2.f
318                    )
319                );
320                cr->paint();
321            }
322            cr->restore();
323        }
324    }
325    
326  #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
327  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)  bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
328  {  {
# Line 229  bool DimRegionChooser::on_draw(const Cai Line 411  bool DimRegionChooser::on_draw(const Cai
411                      dstr = dstrbuf;                      dstr = dstrbuf;
412                      break;                      break;
413                  }                  }
                 layout->set_text(dstr);  
414    
415                    // Since bold font yields in larger label width, we first always
416                    // set the bold text variant, retrieve its dimensions (as worst
417                    // case dimensions of the label) ...
418                    layout->set_markup("<b>" + Glib::ustring(dstr) + "</b>");
419                  Pango::Rectangle rectangle = layout->get_logical_extents();                  Pango::Rectangle rectangle = layout->get_logical_extents();
420                    // ... and then reset the label to regular font style in case
421                    // the line is not selected. Otherwise the right hand side
422                    // actual dimension zones would jump around on selection change.
423                    bool isSelectedLine = (focus_line == i);
424                    if (!isSelectedLine)
425                        layout->set_markup(dstr);
426    
427                  double text_w = double(rectangle.get_width()) / Pango::SCALE;                  double text_w = double(rectangle.get_width()) / Pango::SCALE;
428                  if (text_w > maxwidth) maxwidth = text_w;                  if (text_w > maxwidth) maxwidth = text_w;
429    
# Line 273  bool DimRegionChooser::on_draw(const Cai Line 465  bool DimRegionChooser::on_draw(const Cai
465                  // draw focus rectangle around dimension's label and zones                  // draw focus rectangle around dimension's label and zones
466                  if (has_focus() && focus_line == i) {                  if (has_focus() && focus_line == i) {
467  #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
468                      Gdk::Rectangle farea(0, y, 150, 20);                      Gdk::Rectangle farea(0, y, 150, h);
469                      get_style()->paint_focus(get_window(), get_state(), farea,                      get_style()->paint_focus(get_window(), get_state(), farea,
470                                               *this, "",                                               *this, "",
471                                               0, y, label_width, 20);                                               0, y, label_width, h);
472  #else  #else
473                      get_style_context()->render_focus(cr,                      get_style_context()->render_focus(cr,
474                                                        0, y, label_width, 20);                                                        0, y, label_width, h);
475  #endif  #endif
476                  }                  }
477    
# Line 318  bool DimRegionChooser::on_draw(const Cai Line 510  bool DimRegionChooser::on_draw(const Cai
510                      cr->move_to(label_width + 0.5, y + 1);                      cr->move_to(label_width + 0.5, y + 1);
511                      cr->line_to(label_width + 0.5, y + h - 1);                      cr->line_to(label_width + 0.5, y + h - 1);
512                      int prevX = label_width;                      int prevX = label_width;
513                      int prevUpperLimit = 0;                      int prevUpperLimit = -1;
514    
515                      for (int j = 0 ; j < nbZones ; j++) {                      for (int j = 0 ; j < nbZones ; j++) {
516                          // draw dimension zone's borders for custom splits                          // draw dimension zone's borders for custom splits
# Line 338  bool DimRegionChooser::on_draw(const Cai Line 530  bool DimRegionChooser::on_draw(const Cai
530    
531                          // draw fill for zone                          // draw fill for zone
532                          bool isSelectedZone = this->dimzones[dimension].count(j);                          bool isSelectedZone = this->dimzones[dimension].count(j);
533                          Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);                          bool isMainSelection =
534                          cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);                              this->maindimcase.find(dimension) != this->maindimcase.end() &&
535                                this->maindimcase[dimension] == j;
536                            bool isCheckBoxSelected =
537                                modifyalldimregs ||
538                                (modifybothchannels &&
539                                    dimension == gig::dimension_samplechannel);
540                            if (isMainSelection)
541                                Gdk::Cairo::set_source_rgba(cr, blue);
542                            else if (isSelectedZone)
543                                cr->set_source(blueHatchedSurfacePattern2);
544                            else if (isCheckBoxSelected)
545                                cr->set_source(blueHatchedSurfacePattern);
546                            else
547                                Gdk::Cairo::set_source_rgba(cr, white);
548    
549                            const int wZone = x - prevX - 1;
550    
551                            cr->rectangle(prevX + 1, y + 1, wZone, h - 1);
552                          cr->fill();                          cr->fill();
553    
554                            // draw icons
555                            drawIconsFor(dimension, j, cr, prevX, y, wZone, h);
556    
557                          // draw text showing the beginning of the dimension zone                          // draw text showing the beginning of the dimension zone
558                          // as numeric value to the user                          // as numeric value to the user
559                          {                          {
560                              Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                              Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
561                              layout->set_text(Glib::Ascii::dtostr(prevUpperLimit));                              layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
562                              Gdk::Cairo::set_source_rgba(cr, black);                              Gdk::Cairo::set_source_rgba(cr, black);
                             Pango::Rectangle rect = layout->get_logical_extents();  
563                              // get the text dimensions                              // get the text dimensions
564                              int text_width, text_height;                              int text_width, text_height;
565                              layout->get_pixel_size(text_width, text_height);                              layout->get_pixel_size(text_width, text_height);
566                              // move text to the left end of the dimension zone                              // move text to the left end of the dimension zone
567                              cr->move_to(prevX + 3, y + 1);                              cr->move_to(prevX + 3, y + (h - text_height) / 2);
568  #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
569                              pango_cairo_show_layout(cr->cobj(), layout->gobj());                              pango_cairo_show_layout(cr->cobj(), layout->gobj());
570  #else  #else
# Line 366  bool DimRegionChooser::on_draw(const Cai Line 577  bool DimRegionChooser::on_draw(const Cai
577                              Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                              Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
578                              layout->set_text(Glib::Ascii::dtostr(upperLimit));                              layout->set_text(Glib::Ascii::dtostr(upperLimit));
579                              Gdk::Cairo::set_source_rgba(cr, black);                              Gdk::Cairo::set_source_rgba(cr, black);
                             Pango::Rectangle rect = layout->get_logical_extents();  
580                              // get the text dimensions                              // get the text dimensions
581                              int text_width, text_height;                              int text_width, text_height;
582                              layout->get_pixel_size(text_width, text_height);                              layout->get_pixel_size(text_width, text_height);
583                              // move text to the left end of the dimension zone                              // move text to the left end of the dimension zone
584                              cr->move_to(x - 3 - text_width, y + 1);                              cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
585  #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
586                              pango_cairo_show_layout(cr->cobj(), layout->gobj());                              pango_cairo_show_layout(cr->cobj(), layout->gobj());
587  #else  #else
# Line 396  bool DimRegionChooser::on_draw(const Cai Line 606  bool DimRegionChooser::on_draw(const Cai
606                          cr->stroke();                          cr->stroke();
607    
608                          if (j != 0) {                          if (j != 0) {
609                                const int wZone = x - prevX - 1;
610    
611                              // draw fill for zone                              // draw fill for zone
612                              bool isSelectedZone = this->dimzones[dimension].count(j-1);                              bool isSelectedZone = this->dimzones[dimension].count(j-1);
613                              Gdk::Cairo::set_source_rgba(cr, isSelectedZone ? red : white);                              bool isMainSelection =
614                              cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);                                  this->maindimcase.find(dimension) != this->maindimcase.end() &&
615                                    this->maindimcase[dimension] == (j-1);
616                                bool isCheckBoxSelected =
617                                    modifyalldimregs ||
618                                    (modifybothchannels &&
619                                        dimension == gig::dimension_samplechannel);
620                                if (isMainSelection)
621                                    Gdk::Cairo::set_source_rgba(cr, blue);
622                                else if (isSelectedZone)
623                                    cr->set_source(blueHatchedSurfacePattern2);
624                                else if (isCheckBoxSelected)
625                                    cr->set_source(blueHatchedSurfacePattern);
626                                else
627                                    Gdk::Cairo::set_source_rgba(cr, white);
628                                cr->rectangle(prevX + 1, y + 1, wZone, h - 1);
629                              cr->fill();                              cr->fill();
630    
631                                // draw icons
632                                drawIconsFor(dimension, j - 1, cr, prevX, y, wZone, h);
633    
634                              // draw text showing the beginning of the dimension zone                              // draw text showing the beginning of the dimension zone
635                              // as numeric value to the user                              // as numeric value to the user
636                              {                              {
637                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
638                                  layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));                                  layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
639                                  Gdk::Cairo::set_source_rgba(cr, black);                                  Gdk::Cairo::set_source_rgba(cr, black);
                                 Pango::Rectangle rect = layout->get_logical_extents();  
640                                  // get the text dimensions                                  // get the text dimensions
641                                  int text_width, text_height;                                  int text_width, text_height;
642                                  layout->get_pixel_size(text_width, text_height);                                  layout->get_pixel_size(text_width, text_height);
643                                  // move text to the left end of the dimension zone                                  // move text to the left end of the dimension zone
644                                  cr->move_to(prevX + 3, y + 1);                                  cr->move_to(prevX + 3, y + (h - text_height) / 2);
645  #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
646                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());
647  #else  #else
# Line 426  bool DimRegionChooser::on_draw(const Cai Line 654  bool DimRegionChooser::on_draw(const Cai
654                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
655                                  layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));                                  layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
656                                  Gdk::Cairo::set_source_rgba(cr, black);                                  Gdk::Cairo::set_source_rgba(cr, black);
                                 Pango::Rectangle rect = layout->get_logical_extents();  
657                                  // get the text dimensions                                  // get the text dimensions
658                                  int text_width, text_height;                                  int text_width, text_height;
659                                  layout->get_pixel_size(text_width, text_height);                                  layout->get_pixel_size(text_width, text_height);
660                                  // move text to the left end of the dimension zone                                  // move text to the left end of the dimension zone
661                                  cr->move_to(x - 3 - text_width, y + 1);                                  cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
662  #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
663                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());                                  pango_cairo_show_layout(cr->cobj(), layout->gobj());
664  #else  #else
# Line 469  void DimRegionChooser::set_region(gig::R Line 696  void DimRegionChooser::set_region(gig::R
696          }          }
697      }      }
698      dimregion_selected();      dimregion_selected();
699      set_size_request(800, region ? nbDimensions * 20 : 0);      set_size_request(800, region ? nbDimensions * h : 0);
700    
701      labels_changed = true;      labels_changed = true;
702      queue_resize();      queue_resize();
# Line 511  void DimRegionChooser::get_dimregions(co Line 738  void DimRegionChooser::get_dimregions(co
738    
739  void DimRegionChooser::update_after_resize()  void DimRegionChooser::update_after_resize()
740  {  {
741      if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {      const uint8_t upperLimit = resize.pos - 1;
742        gig::Instrument* instr = (gig::Instrument*)region->GetParent();
743    
744          int bitpos = 0;      int bitpos = 0;
745          for (int j = 0 ; j < resize.dimension ; j++) {      for (int j = 0 ; j < resize.dimension ; j++) {
746              bitpos += region->pDimensionDefinitions[j].bits;          bitpos += region->pDimensionDefinitions[j].bits;
747          }      }
748    
749        const int stereobitpos =
750            (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
751    
752        // the velocity dimension must be handled differently than all other
753        // dimension types, because
754        // 1. it is currently the only dimension type which allows different zone
755        //    sizes for different cases
756        // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
757        if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
758          int mask =          int mask =
759              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);              ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
760          int c = maindimregno & mask; // mask away this dimension          int c = maindimregno & mask; // mask away this dimension
# Line 542  void DimRegionChooser::update_after_resi Line 780  void DimRegionChooser::update_after_resi
780              }              }
781          }          }
782    
783          gig::DimensionRegion* d = region->pDimensionRegions[c + resize.offset];          int index = c + (resize.zone << bitpos);
784            gig::DimensionRegion* d = region->pDimensionRegions[index];
785          // update both v2 and v3 values          // update both v2 and v3 values
786          d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;          d->DimensionUpperLimits[resize.dimension] = upperLimit;
787          d->VelocityUpperLimit = resize.pos - 1;          d->VelocityUpperLimit = upperLimit;
788            if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
789                gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
790                d->DimensionUpperLimits[resize.dimension] = upperLimit;
791                d->VelocityUpperLimit = upperLimit;
792            }
793    
794            if (modifyalldimregs) {
795                gig::Region* rgn = NULL;
796                for (int key = 0; key < 128; ++key) {
797                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
798                    rgn = instr->GetRegion(key);
799                    if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
800                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
801                    if (!dimdef) continue;
802                    if (dimdef->zones != resize.dimensionDef.zones) continue;
803                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
804                    assert(iDim >= 0 && iDim < rgn->Dimensions);
805    
806                    // the dimension layout might be completely different in this
807                    // region, so we have to recalculate bitpos etc for this region
808                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
809                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
810                    const int selection = resize.zone << bitpos;
811    
812                    // primitive and inefficient loop implementation, however due to
813                    // this circumstance the loop code is much simpler, and its lack
814                    // of runtime efficiency should not be notable in practice
815                    for (int idr = 0; idr < 256; ++idr) {
816                        const int index = (idr & stencil) | selection;
817                        assert(index >= 0 && index < 256);
818                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
819                        if (!dr) continue;
820                        dr->DimensionUpperLimits[iDim] = upperLimit;
821                        d->VelocityUpperLimit = upperLimit;
822                    }
823                }
824            } else if (modifyallregions) { // implies modifyalldimregs is false ...
825                // resolve the precise case we need to modify for all other regions
826                DimensionCase dimCase = dimensionCaseOf(d);
827                // apply the velocity upper limit change to that resolved dim case
828                // of all regions ...
829                gig::Region* rgn = NULL;
830                for (int key = 0; key < 128; ++key) {
831                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
832                    rgn = instr->GetRegion(key);
833                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
834                    if (!dimdef) continue;
835                    if (dimdef->zones != resize.dimensionDef.zones) continue;
836                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
837                    assert(iDim >= 0 && iDim < rgn->Dimensions);
838    
839                    std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
840                    for (int i = 0; i < dimrgns.size(); ++i) {
841                        gig::DimensionRegion* dr = dimrgns[i];
842                        dr->DimensionUpperLimits[iDim] = upperLimit;
843                        dr->VelocityUpperLimit = upperLimit;
844                    }
845                }
846            }
847      } else {      } else {
848          for (int i = 0 ; i < region->DimensionRegions ; ) {          for (int i = 0 ; i < region->DimensionRegions ; ) {
   
849              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
850                  // the dimension didn't previously have custom                  // the dimension didn't previously have custom
851                  // limits, so we have to set default limits for                  // limits, so we have to set default limits for
852                  // all the dimension regions                  // all the dimension regions
                 int bitpos = 0;  
                 for (int j = 0 ; j < resize.dimension ; j++) {  
                     bitpos += region->pDimensionDefinitions[j].bits;  
                 }  
853                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
854    
855                  for (int j = 0 ; j < nbZones ; j++) {                  for (int j = 0 ; j < nbZones ; j++) {
# Line 565  void DimRegionChooser::update_after_resi Line 857  void DimRegionChooser::update_after_resi
857                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
858                  }                  }
859              }              }
860              gig::DimensionRegion* d = region->pDimensionRegions[i + resize.offset];              int index = i + (resize.zone << bitpos);
861              d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              gig::DimensionRegion* d = region->pDimensionRegions[index];
862                d->DimensionUpperLimits[resize.dimension] = upperLimit;
863    #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
864                if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
865                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
866                    d->DimensionUpperLimits[resize.dimension] = upperLimit;
867                }
868    #endif
869              int bitpos = 0;              int bitpos = 0;
870              int j;              int j;
871              for (j = 0 ; j < region->Dimensions ; j++) {              for (j = 0 ; j < region->Dimensions ; j++) {
# Line 581  void DimRegionChooser::update_after_resi Line 879  void DimRegionChooser::update_after_resi
879              if (j == region->Dimensions) break;              if (j == region->Dimensions) break;
880              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);              i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
881          }          }
882    
883            if (modifyallregions) { // TODO: this code block could be merged with the similar (and more generalized) code block of the velocity dimension above
884                gig::Region* rgn = NULL;
885                for (int key = 0; key < 128; ++key) {
886                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
887                    rgn = instr->GetRegion(key);
888                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
889                    if (!dimdef) continue;
890                    if (dimdef->zones != resize.dimensionDef.zones) continue;
891                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
892                    assert(iDim >= 0 && iDim < rgn->Dimensions);
893    
894                    // the dimension layout might be completely different in this
895                    // region, so we have to recalculate bitpos etc for this region
896                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
897                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
898                    const int selection = resize.zone << bitpos;
899    
900                    // this loop implementation is less efficient than the above's
901                    // loop implementation (which skips unnecessary dimension regions)
902                    // however this code is much simpler, and its lack of runtime
903                    // efficiency should not be notable in practice
904                    for (int idr = 0; idr < 256; ++idr) {
905                        const int index = (idr & stencil) | selection;
906                        assert(index >= 0 && index < 256);
907                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
908                        if (!dr) continue;
909                        dr->DimensionUpperLimits[iDim] = upperLimit;
910                    }
911                }
912            }
913      }      }
914  }  }
915    
# Line 809  bool DimRegionChooser::is_in_resize_zone Line 1138  bool DimRegionChooser::is_in_resize_zone
1138                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
1139                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
1140                      resize.dimension = dim;                      resize.dimension = dim;
1141                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
1142                        resize.zone = iZone;
1143                      resize.pos = limit;                      resize.pos = limit;
1144                      resize.min = prev_limit;                      resize.min = prev_limit;
1145    
# Line 850  sigc::signal<void>& DimRegionChooser::si Line 1180  sigc::signal<void>& DimRegionChooser::si
1180    
1181  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
1182  {  {
1183      // 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
1184      // fokus.      // to set focus
1185      if (direction == Gtk::DIR_TAB_FORWARD ||      if (direction == Gtk::DIR_TAB_FORWARD ||
1186          direction == Gtk::DIR_DOWN) {          direction == Gtk::DIR_DOWN) {
1187          if (!has_focus()) {          if (!has_focus()) {
# Line 883  bool DimRegionChooser::on_focus(Gtk::Dir Line 1213  bool DimRegionChooser::on_focus(Gtk::Dir
1213              }              }
1214          }          }
1215      } else if (!has_focus()) {      } else if (!has_focus()) {
1216          // TODO: kolla att focus_line finns!          // TODO: check that focus_line exists
1217          grab_focus();          grab_focus();
1218          return true;          return true;
1219      } else {      } else {
1220          // TODO: öka eller minska värde!          // TODO: increase or decrease value
1221      }      }
1222        return false;
1223  }  }
1224    
1225  void DimRegionChooser::split_dimension_zone() {      void DimRegionChooser::split_dimension_zone() {    
1226      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1227      try {      try {
1228          region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);          if (!modifyallregions) {
1229                region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1230            } else {
1231                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1232                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1233                assert(pMaindimdef != NULL);
1234                // retain structure by value since the original region will be
1235                // modified in the loop below as well
1236                gig::dimension_def_t maindimdef = *pMaindimdef;
1237                std::vector<gig::Region*> ignoredAll;
1238                std::vector<gig::Region*> ignoredMinor;
1239                std::vector<gig::Region*> ignoredCritical;
1240                gig::Region* rgn = NULL;
1241                for (int key = 0; key < 128; ++key) {
1242                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1243                    rgn = instr->GetRegion(key);
1244    
1245                    // ignore all regions which do not exactly match the dimension
1246                    // layout of the selected region where this operation was emitted
1247                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1248                    if (!dimdef) {
1249                        ignoredAll.push_back(rgn);
1250                        ignoredMinor.push_back(rgn);
1251                        continue;
1252                    }
1253                    if (dimdef->zones != maindimdef.zones) {
1254                        ignoredAll.push_back(rgn);
1255                        ignoredCritical.push_back(rgn);
1256                        continue;
1257                    }
1258    
1259                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1260                }
1261                if (!ignoredAll.empty()) {
1262                    Glib::ustring txt;
1263                    if (ignoredCritical.empty())
1264                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1265                    else if (ignoredMinor.empty())
1266                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1267                    else
1268                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1269                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1270                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1271                    Gtk::MessageDialog msg(txt, false, type);
1272                    msg.run();
1273                }
1274            }
1275      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1276          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1277          msg.run();          msg.run();
# Line 909  void DimRegionChooser::split_dimension_z Line 1286  void DimRegionChooser::split_dimension_z
1286  void DimRegionChooser::delete_dimension_zone() {  void DimRegionChooser::delete_dimension_zone() {
1287      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);      printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1288      try {      try {
1289          region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);          if (!modifyallregions) {
1290                region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1291            } else {
1292                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1293                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1294                assert(pMaindimdef != NULL);
1295                // retain structure by value since the original region will be
1296                // modified in the loop below as well
1297                gig::dimension_def_t maindimdef = *pMaindimdef;
1298                std::vector<gig::Region*> ignoredAll;
1299                std::vector<gig::Region*> ignoredMinor;
1300                std::vector<gig::Region*> ignoredCritical;
1301                gig::Region* rgn = NULL;
1302                for (int key = 0; key < 128; ++key) {
1303                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1304                    rgn = instr->GetRegion(key);
1305    
1306                    // ignore all regions which do not exactly match the dimension
1307                    // layout of the selected region where this operation was emitted
1308                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1309                    if (!dimdef) {
1310                        ignoredAll.push_back(rgn);
1311                        ignoredMinor.push_back(rgn);
1312                        continue;
1313                    }
1314                    if (dimdef->zones != maindimdef.zones) {
1315                        ignoredAll.push_back(rgn);
1316                        ignoredCritical.push_back(rgn);
1317                        continue;
1318                    }
1319    
1320                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1321                }
1322                if (!ignoredAll.empty()) {
1323                    Glib::ustring txt;
1324                    if (ignoredCritical.empty())
1325                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1326                    else if (ignoredMinor.empty())
1327                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1328                    else
1329                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1330                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1331                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1332                    Gtk::MessageDialog msg(txt, false, type);
1333                    msg.run();
1334                }
1335            }
1336      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
1337          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1338          msg.run();          msg.run();
# Line 921  void DimRegionChooser::delete_dimension_ Line 1344  void DimRegionChooser::delete_dimension_
1344      refresh_all();      refresh_all();
1345  }  }
1346    
1347    // Cmd key on Mac, Ctrl key on all other OSs
1348    static const guint primaryKeyL =
1349        #if defined(__APPLE__)
1350        GDK_KEY_Meta_L;
1351        #else
1352        GDK_KEY_Control_L;
1353        #endif
1354    
1355    static const guint primaryKeyR =
1356        #if defined(__APPLE__)
1357        GDK_KEY_Meta_R;
1358        #else
1359        GDK_KEY_Control_R;
1360        #endif
1361    
1362  bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {  bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1363      //printf("key down\n");      //printf("key down 0x%x\n", key->keyval);
1364      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1365          multiSelectKeyDown = true;          multiSelectKeyDown = true;
1366        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1367            primaryKeyDown = true;
1368        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1369            shiftKeyDown = true;
1370    
1371        //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
1372        /*if (key->keyval == GDK_KEY_Left)
1373            select_prev_dimzone();
1374        if (key->keyval == GDK_KEY_Right)
1375            select_next_dimzone();
1376        if (key->keyval == GDK_KEY_Up)
1377            select_prev_dimension();
1378        if (key->keyval == GDK_KEY_Down)
1379            select_next_dimension();*/
1380        return false;
1381  }  }
1382    
1383  bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {  bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1384      //printf("key up\n");      //printf("key up 0x%x\n", key->keyval);
1385      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)      if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1386          multiSelectKeyDown = false;          multiSelectKeyDown = false;
1387        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1388            primaryKeyDown = false;
1389        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1390            shiftKeyDown = false;
1391    
1392        if (!has_focus()) return false;
1393    
1394        // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow
1395        // (which is supposed to switch between regions)
1396        if (primaryKeyDown) return false;
1397    
1398        // avoid conflict with Alt+Shift+Left and Alt+Shift+Right accelerators on
1399        // mainwindow
1400        if (shiftKeyDown) return false;
1401    
1402        if (key->keyval == GDK_KEY_Left)
1403            select_prev_dimzone();
1404        if (key->keyval == GDK_KEY_Right)
1405            select_next_dimzone();
1406        if (key->keyval == GDK_KEY_Up)
1407            select_prev_dimension();
1408        if (key->keyval == GDK_KEY_Down)
1409            select_next_dimension();
1410    
1411        return false;
1412    }
1413    
1414    void DimRegionChooser::resetSelectedZones() {
1415        this->dimzones.clear();
1416        if (!region) {
1417            queue_draw(); // redraw required parts
1418            return;
1419        }
1420        if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1421            queue_draw(); // redraw required parts
1422            return;
1423        }
1424        if (!region->pDimensionRegions[maindimregno]) {
1425            queue_draw(); // redraw required parts
1426            return;
1427        }
1428        gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1429    
1430        bool isValidZone;
1431        this->maindimcase = dimensionCaseOf(dimrgn);
1432    
1433        for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1434             it != this->maindimcase.end(); ++it)
1435        {
1436            this->dimzones[it->first].insert(it->second);
1437        }
1438    
1439        // redraw required parts
1440        queue_draw();
1441    }
1442    
1443    bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1444        if (!region) return false; //.selection failed
1445    
1446        for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1447            if (region->pDimensionRegions[dr] == dimrgn) {
1448                // reset dim region zone selection to the requested specific dim region case
1449                maindimregno = dr;
1450                resetSelectedZones();
1451    
1452                // emit signal that dimregion selection has changed, for external entities
1453                dimregion_selected();
1454    
1455                return true; // selection success
1456            }
1457        }
1458    
1459        return false; //.selection failed
1460    }
1461    
1462    void DimRegionChooser::select_next_dimzone(bool add) {
1463        select_dimzone_by_dir(+1, add);
1464    }
1465    
1466    void DimRegionChooser::select_prev_dimzone(bool add) {
1467        select_dimzone_by_dir(-1, add);
1468    }
1469    
1470    void DimRegionChooser::select_dimzone_by_dir(int dir, bool add) {
1471        if (!region) return;
1472        if (!region->Dimensions) return;
1473        if (focus_line < 0) focus_line = 0;
1474        if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1475    
1476        maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1477        if (maindimtype == gig::dimension_none) {
1478            printf("maindimtype -> none\n");
1479            return;
1480        }
1481    
1482        if (maindimcase.empty()) {
1483            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1484            if (maindimcase.empty()) {
1485                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1486                return;
1487            }
1488        }
1489    
1490        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1491        if (z < 0) z = 0;
1492        if (z >= region->pDimensionDefinitions[focus_line].zones)
1493            z = region->pDimensionDefinitions[focus_line].zones - 1;
1494    
1495        maindimcase[maindimtype] = z;
1496    
1497        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1498        if (!dr) {
1499            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1500            return;
1501        }
1502    
1503        maindimregno = getDimensionRegionIndex(dr);
1504    
1505        if (!add) {
1506            // reset selected dimregion zones
1507            dimzones.clear();
1508        }
1509        for (DimensionCase::const_iterator it = maindimcase.begin();
1510             it != maindimcase.end(); ++it)
1511        {
1512            dimzones[it->first].insert(it->second);
1513        }
1514    
1515        dimregion_selected();
1516    
1517        // disabled: would overwrite dimregno with wrong value
1518        //refresh_all();
1519        // so requesting just a raw repaint instead:
1520        queue_draw();
1521    }
1522    
1523    void DimRegionChooser::select_next_dimension() {
1524        if (!region) return;
1525        focus_line++;
1526        if (focus_line >= region->Dimensions)
1527            focus_line = region->Dimensions - 1;
1528        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1529        queue_draw();
1530    }
1531    
1532    void DimRegionChooser::select_prev_dimension() {
1533        if (!region) return;
1534        focus_line--;
1535        if (focus_line < 0)
1536            focus_line = 0;
1537        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1538        queue_draw();
1539  }  }
1540    
1541  gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {  gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {

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

  ViewVC Help
Powered by ViewVC