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

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

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

revision 2246 by persson, Fri Aug 19 10:55:41 2011 UTC revision 3340 by schoenebeck, Mon Jul 31 11:20:18 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2011 Andreas Persson   * Copyright (C) 2006-2017 Andreas Persson
3   *   *
4   * This program is free software; you can redistribute it and/or   * This program is free software; you can redistribute it and/or
5   * modify it under the terms of the GNU General Public License as   * modify it under the terms of the GNU General Public License as
# Line 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
20    #include "global.h"
21    #include <gtkmm/box.h>
22  #include "dimregionchooser.h"  #include "dimregionchooser.h"
23  #include <cairomm/context.h>  #include <cairomm/context.h>
24    #include <cairomm/surface.h>
25  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
26  #include <gdkmm/general.h>  #include <gdkmm/general.h>
27    #include <glibmm/stringutils.h>
28    #include <gtkmm/stock.h>
29    #include <glibmm/ustring.h>
30    #include <gtkmm/messagedialog.h>
31    #include <assert.h>
32    
33    #include "gfx/builtinpix.h"
34    
35    //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
36    static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
37        DimensionCase dimCase;
38        if (!dr) {
39            *isValidZone = false;
40            return dimCase;
41        }
42    
43  #include "global.h"      gig::Region* rgn = (gig::Region*) dr->GetParent();
44    
45        // find the dimension region index of the passed dimension region
46        int drIndex;
47        for (drIndex = 0; drIndex < 256; ++drIndex)
48            if (rgn->pDimensionRegions[drIndex] == dr)
49                break;
50    
51        // not found in region, something's horribly wrong
52        if (drIndex == 256) {
53            fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
54            *isValidZone = false;
55            return DimensionCase();
56        }
57    
58        for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
59            const int bits = rgn->pDimensionDefinitions[d].bits;
60            dimCase[rgn->pDimensionDefinitions[d].dimension] =
61                (drIndex >> baseBits) & ((1 << bits) - 1);
62            baseBits += bits;
63            // there are also DimensionRegion objects of unused zones, skip them
64            if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
65                *isValidZone = false;
66                return DimensionCase();
67            }
68        }
69    
70        *isValidZone = true;
71        return dimCase;
72    }
73    
74  DimRegionChooser::DimRegionChooser() :  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      dimregno = -1;      maindimregno = -1;
176        maindimtype = gig::dimension_none; // initialize with invalid dimension type
177      focus_line = 0;      focus_line = 0;
178      resize.active = false;      resize.active = false;
179      cursor_is_resize = false;      cursor_is_resize = false;
180      h = 20;      h = 24;
181        multiSelectKeyDown = false;
182        primaryKeyDown = false;
183        shiftKeyDown = false;
184        modifybothchannels = modifyalldimregs = modifybothchannels = false;
185      set_can_focus();      set_can_focus();
186    
187        const Glib::ustring txtUseCheckBoxAllRegions =
188            _("Use checkbox 'all regions' to control whether this should apply to all regions.");
189    
190        actionGroup = Gtk::ActionGroup::create();
191        actionSplitDimZone = Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
192        actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
193        actionGroup->add(
194            actionSplitDimZone,
195            sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
196        );
197        actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
198        actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
199        actionGroup->add(
200            actionDeleteDimZone,
201            sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
202        );
203    
204        uiManager = Gtk::UIManager::create();
205        uiManager->insert_action_group(actionGroup);
206        Glib::ustring ui_info =
207            "<ui>"
208            "  <popup name='PopupMenuInsideDimRegion'>"
209            "    <menuitem action='SplitDimZone'/>"
210            "    <menuitem action='DeleteDimZone'/>"
211            "  </popup>"
212    //         "  <popup name='PopupMenuOutsideDimRegion'>"
213    //         "    <menuitem action='Add'/>"
214    //         "  </popup>"
215            "</ui>";
216        uiManager->add_ui_from_string(ui_info);
217    
218        popup_menu_inside_dimregion = dynamic_cast<Gtk::Menu*>(
219            uiManager->get_widget("/PopupMenuInsideDimRegion"));
220    //     popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(
221    //         uiManager->get_widget("/PopupMenuOutsideDimRegion"));
222    
223      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
224                 Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_HINT_MASK);
225    
     for (int i = 0 ; i < 256 ; i++) dimvalue[i] = 0;  
226      labels_changed = true;      labels_changed = true;
227    
228        set_tooltip_text(_(
229            "Right click here for options on altering dimension zones. Press and "
230            "hold CTRL key for selecting multiple dimension zones simultaniously."
231        ));
232        
233        window.signal_key_press_event().connect(
234            sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)
235        );
236        window.signal_key_release_event().connect(
237            sigc::mem_fun(*this, &DimRegionChooser::onKeyReleased)
238        );
239  }  }
240    
241  DimRegionChooser::~DimRegionChooser()  DimRegionChooser::~DimRegionChooser()
242  {  {
243  }  }
244    
245    void DimRegionChooser::setModifyBothChannels(bool b) {
246        modifybothchannels = b;
247        // redraw required parts
248        queue_draw();
249    }
250    
251    void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
252        modifyalldimregs = b;
253        // redraw required parts
254        queue_draw();
255    }
256    
257    void DimRegionChooser::setModifyAllRegions(bool b) {
258        modifyallregions = b;
259    
260        actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
261        actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
262    
263        // redraw required parts
264        queue_draw();
265    }
266    
267    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 58  bool DimRegionChooser::on_expose_event(G Line 333  bool DimRegionChooser::on_expose_event(G
333    
334      const Cairo::RefPtr<Cairo::Context>& cr =      const Cairo::RefPtr<Cairo::Context>& cr =
335          get_window()->create_cairo_context();          get_window()->create_cairo_context();
 #if 0  
 }  
 #endif  
336  #else  #else
337  bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)  bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
338  {  {
# Line 139  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 176  bool DimRegionChooser::on_draw(const Cai Line 458  bool DimRegionChooser::on_draw(const Cai
458      for (int i = 0 ; i < region->Dimensions ; i++) {      for (int i = 0 ; i < region->Dimensions ; i++) {
459          int nbZones = region->pDimensionDefinitions[i].zones;          int nbZones = region->pDimensionDefinitions[i].zones;
460          if (nbZones) {          if (nbZones) {
461                const gig::dimension_t dimension = region->pDimensionDefinitions[i].dimension;
462    
463              if (y >= clipy2) break;              if (y >= clipy2) break;
464              if (y + h > clipy1) {              if (y + h > clipy1) {
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 206  bool DimRegionChooser::on_draw(const Cai Line 490  bool DimRegionChooser::on_draw(const Cai
490                  cr->fill();                  cr->fill();
491    
492                  int c = 0;                  int c = 0;
493                  if (dimregno >= 0) {                  if (maindimregno >= 0) {
494                      int mask =                      int mask =
495                          ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<                          ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
496                            bitpos);                            bitpos);
497                      c = dimregno & mask; // mask away this dimension                      c = maindimregno & mask; // mask away this dimension
498                  }                  }
499                  bool customsplits =                  bool customsplits =
500                      ((region->pDimensionDefinitions[i].split_type ==                      ((region->pDimensionDefinitions[i].split_type ==
# Line 220  bool DimRegionChooser::on_draw(const Cai Line 504  bool DimRegionChooser::on_draw(const Cai
504                        gig::dimension_velocity &&                        gig::dimension_velocity &&
505                        region->pDimensionRegions[c]->VelocityUpperLimit));                        region->pDimensionRegions[c]->VelocityUpperLimit));
506    
507                  // draw dimension's zone borders                  // draw dimension zones
508                  Gdk::Cairo::set_source_rgba(cr, black);                  Gdk::Cairo::set_source_rgba(cr, black);
509                  if (customsplits) {                  if (customsplits) {
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;
513                        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
517                          gig::DimensionRegion* d =                          gig::DimensionRegion* d =
518                              region->pDimensionRegions[c + (j << bitpos)];                              region->pDimensionRegions[c + (j << bitpos)];
519                          int upperLimit = d->DimensionUpperLimits[i];                          int upperLimit = d->DimensionUpperLimits[i];
# Line 236  bool DimRegionChooser::on_draw(const Cai Line 523  bool DimRegionChooser::on_draw(const Cai
523                              label_width;                              label_width;
524                          if (x >= clipx2) break;                          if (x >= clipx2) break;
525                          if (x < clipx1) continue;                          if (x < clipx1) continue;
526                            Gdk::Cairo::set_source_rgba(cr, black);
527                          cr->move_to(x + 0.5, y + 1);                          cr->move_to(x + 0.5, y + 1);
528                          cr->line_to(x + 0.5, y + h - 1);                          cr->line_to(x + 0.5, y + h - 1);
529                            cr->stroke();
530    
531                            // draw fill for zone
532                            bool isSelectedZone = this->dimzones[dimension].count(j);
533                            bool isMainSelection =
534                                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();
553    
554                            // draw icons
555                            drawIconsFor(dimension, j, cr, prevX, y, wZone, h);
556    
557                            // draw text showing the beginning of the dimension zone
558                            // as numeric value to the user
559                            {
560                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
561                                layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
562                                Gdk::Cairo::set_source_rgba(cr, black);
563                                // get the text dimensions
564                                int text_width, text_height;
565                                layout->get_pixel_size(text_width, text_height);
566                                // move text to the left end of the dimension zone
567                                cr->move_to(prevX + 3, y + (h - text_height) / 2);
568    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
569                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
570    #else
571                                layout->show_in_cairo_context(cr);
572    #endif
573                            }
574                            // draw text showing the end of the dimension zone
575                            // as numeric value to the user
576                            {
577                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
578                                layout->set_text(Glib::Ascii::dtostr(upperLimit));
579                                Gdk::Cairo::set_source_rgba(cr, black);
580                                // get the text dimensions
581                                int text_width, text_height;
582                                layout->get_pixel_size(text_width, text_height);
583                                // move text to the left end of the dimension zone
584                                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
586                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
587    #else
588                                layout->show_in_cairo_context(cr);
589    #endif
590                            }
591    
592                            prevX = x;
593                            prevUpperLimit = upperLimit;
594                      }                      }
595                  } else {                  } else {
596                        int prevX = 0;
597                      for (int j = 0 ; j <= nbZones ; j++) {                      for (int j = 0 ; j <= nbZones ; j++) {
598                            // draw dimension zone's borders for normal splits
599                          int x = int((w - label_width - 1) * j /                          int x = int((w - label_width - 1) * j /
600                                      double(nbZones) + 0.5) + label_width;                                      double(nbZones) + 0.5) + label_width;
601                          if (x >= clipx2) break;                          if (x >= clipx2) break;
602                          if (x < clipx1) continue;                          if (x < clipx1) continue;
603                            Gdk::Cairo::set_source_rgba(cr, black);
604                          cr->move_to(x + 0.5, y + 1);                          cr->move_to(x + 0.5, y + 1);
605                          cr->line_to(x + 0.5, y + h - 1);                          cr->line_to(x + 0.5, y + h - 1);
606                      }                          cr->stroke();
                 }  
                 cr->stroke();  
607    
608                  // draw fill for currently selected zone                          if (j != 0) {
609                  if (dimregno >= 0) {                              const int wZone = x - prevX - 1;
610                      Gdk::Cairo::set_source_rgba(cr, red);  
611                      int dr = (dimregno >> bitpos) &                              // draw fill for zone
612                          ((1 << region->pDimensionDefinitions[i].bits) - 1);                              bool isSelectedZone = this->dimzones[dimension].count(j-1);
613                      if (customsplits) {                              bool isMainSelection =
614                          int x1 = label_width;                                  this->maindimcase.find(dimension) != this->maindimcase.end() &&
615                          for (int j = 0 ; j < nbZones && x1 + 1 < clipx2 ; j++) {                                  this->maindimcase[dimension] == (j-1);
616                              gig::DimensionRegion* d =                              bool isCheckBoxSelected =
617                                  region->pDimensionRegions[c + (j << bitpos)];                                  modifyalldimregs ||
618                              int upperLimit = d->DimensionUpperLimits[i];                                  (modifybothchannels &&
619                              if (!upperLimit) {                                      dimension == gig::dimension_samplechannel);
620                                  upperLimit = d->VelocityUpperLimit;                              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();
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
635                                // as numeric value to the user
636                                {
637                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
638                                    layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
639                                    Gdk::Cairo::set_source_rgba(cr, black);
640                                    // get the text dimensions
641                                    int text_width, text_height;
642                                    layout->get_pixel_size(text_width, text_height);
643                                    // move text to the left end of the dimension zone
644                                    cr->move_to(prevX + 3, y + (h - text_height) / 2);
645    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
646                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
647    #else
648                                    layout->show_in_cairo_context(cr);
649    #endif
650                              }                              }
651                              int v = upperLimit + 1;                              // draw text showing the end of the dimension zone
652                              int x2 = int((w - label_width - 1) * v / 128.0 +                              // as numeric value to the user
653                                           0.5) + label_width;                              {
654                              if (j == dr && x1 < x2) {                                  Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
655                                  cr->rectangle(x1 + 1, y + 1,                                  layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
656                                                (x2 - x1) - 1, h - 2);                                  Gdk::Cairo::set_source_rgba(cr, black);
657                                  cr->fill();                                  // get the text dimensions
658                                  break;                                  int text_width, text_height;
659                                    layout->get_pixel_size(text_width, text_height);
660                                    // move text to the left end of the dimension zone
661                                    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
663                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
664    #else
665                                    layout->show_in_cairo_context(cr);
666    #endif
667                              }                              }
                             x1 = x2;  
                         }  
                     } else {  
                         if (dr < nbZones) {  
                             int x1 = int((w - label_width - 1) * dr /  
                                          double(nbZones) + 0.5);  
                             int x2 = int((w - label_width - 1) * (dr + 1) /  
                                          double(nbZones) + 0.5);  
                             cr->rectangle(label_width + x1 + 1, y + 1,  
                                           (x2 - x1) - 1, h - 2);  
                             cr->fill();  
668                          }                          }
669                      }                          prevX = x;
670                        }      
671                  }                  }
672              }              }
   
673              y += h;              y += h;
674          }          }
675          bitpos += region->pDimensionDefinitions[i].bits;          bitpos += region->pDimensionDefinitions[i].bits;
# Line 301  bool DimRegionChooser::on_draw(const Cai Line 681  bool DimRegionChooser::on_draw(const Cai
681  void DimRegionChooser::set_region(gig::Region* region)  void DimRegionChooser::set_region(gig::Region* region)
682  {  {
683      this->region = region;      this->region = region;
684      dimregno = 0;      maindimregno = 0;
685      nbDimensions = 0;      nbDimensions = 0;
686      if (region) {      if (region) {
687          int bitcount = 0;          int bitcount = 0;
# Line 309  void DimRegionChooser::set_region(gig::R Line 689  void DimRegionChooser::set_region(gig::R
689              if (region->pDimensionDefinitions[dim].bits == 0) continue;              if (region->pDimensionDefinitions[dim].bits == 0) continue;
690              nbDimensions++;              nbDimensions++;
691    
692              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
693                               region->pDimensionDefinitions[dim].zones - 1);                               region->pDimensionDefinitions[dim].zones - 1);
694              dimregno |= (z << bitcount);              maindimregno |= (z << bitcount);
695              bitcount += region->pDimensionDefinitions[dim].bits;              bitcount += region->pDimensionDefinitions[dim].bits;
696          }          }
         dimreg = region->pDimensionRegions[dimregno];  
     } else {  
         dimreg = 0;  
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();
703        queue_draw();
704  }  }
705    
706    void DimRegionChooser::refresh_all() {
707        set_region(region);
708    }
709    
710  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
711                                        std::set<gig::DimensionRegion*>& dimregs) const                                        std::set<gig::DimensionRegion*>& dimregs) const
712  {  {
713      int dimregno = 0;      for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
714      int bitcount = 0;          gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
715      int stereo_bit = 0;          if (!dimRgn) continue;
716      for (int dim = 0 ; dim < region->Dimensions ; dim++) {          bool isValidZone;
717          if (region->pDimensionDefinitions[dim].bits == 0) continue;          std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
718          if (stereo &&          if (!isValidZone) continue;
719              region->pDimensionDefinitions[dim].dimension == gig::dimension_samplechannel) {          for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
720              stereo_bit = (1 << bitcount);               it != dimCase.end(); ++it)
721          } else {          {
722              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
723                               region->pDimensionDefinitions[dim].zones - 1);  
724              dimregno |= (z << bitcount);              std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
725                    this->dimzones.find(it->first);
726                if (itSelectedDimension != this->dimzones.end() &&
727                    itSelectedDimension->second.count(it->second)) continue; // is selected
728    
729                goto notSelected;
730          }          }
731          bitcount += region->pDimensionDefinitions[dim].bits;  
732            dimregs.insert(dimRgn);
733    
734            notSelected:
735            ;
736      }      }
     dimregs.insert(region->pDimensionRegions[dimregno]);  
     if (stereo_bit) dimregs.insert(region->pDimensionRegions[dimregno | stereo_bit]);  
737  }  }
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 = dimregno & mask; // mask away this dimension          int c = maindimregno & mask; // mask away this dimension
761    
762          if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {          if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
763              // the velocity dimension didn't previously have              // the velocity dimension didn't previously have
# Line 381  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 404  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 420  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 485  bool DimRegionChooser::on_button_press_e Line 975  bool DimRegionChooser::on_button_press_e
975              }              }
976    
977              int i = dim;              int i = dim;
978              if (dimregno < 0) dimregno = 0;              if (maindimregno < 0) maindimregno = 0;
979              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
980              int c = dimregno & mask; // mask away this dimension              int c = this->maindimregno & mask; // mask away this dimension
981    
982              bool customsplits =              bool customsplits =
983                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
# Line 517  bool DimRegionChooser::on_button_press_e Line 1007  bool DimRegionChooser::on_button_press_e
1007                     region->pDimensionDefinitions[dim].split_type,                     region->pDimensionDefinitions[dim].split_type,
1008                     region->pDimensionDefinitions[dim].zones,                     region->pDimensionDefinitions[dim].zones,
1009                     region->pDimensionDefinitions[dim].zone_size);                     region->pDimensionDefinitions[dim].zone_size);
1010              dimvalue[region->pDimensionDefinitions[dim].dimension] = z;              this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
1011                this->maindimregno = c | (z << bitpos);
1012              dimregno = c | (z << bitpos);              this->maindimtype = region->pDimensionDefinitions[dim].dimension;
1013    
1014                if (multiSelectKeyDown) {
1015                    if (dimzones[this->maindimtype].count(z)) {
1016                        if (dimzones[this->maindimtype].size() > 1) {
1017                            dimzones[this->maindimtype].erase(z);
1018                        }
1019                    } else {
1020                        dimzones[this->maindimtype].insert(z);
1021                    }
1022                } else {
1023                    this->dimzones.clear();
1024                    for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1025                         it != this->maindimcase.end(); ++it)
1026                    {
1027                        this->dimzones[it->first].insert(it->second);
1028                    }
1029                }
1030    
1031              focus_line = dim;              focus_line = dim;
1032              if (has_focus()) queue_draw();              if (has_focus()) queue_draw();
1033              else grab_focus();              else grab_focus();
             dimreg = region->pDimensionRegions[dimregno];  
1034              dimregion_selected();              dimregion_selected();
1035    
1036                if (event->button == 3) {
1037                    printf("dimregion right click\n");
1038                    popup_menu_inside_dimregion->popup(event->button, event->time);
1039                }
1040    
1041                queue_draw();
1042          }          }
1043      }      }
1044      return true;      return true;
# Line 563  bool DimRegionChooser::on_motion_notify_ Line 1076  bool DimRegionChooser::on_motion_notify_
1076    
1077              resize.pos = k;              resize.pos = k;
1078              update_after_resize();              update_after_resize();
1079              get_window()->invalidate_rect(rect, false);              get_window()->invalidate_rect(rect, false); // not sufficient ...
1080                queue_draw(); // ... so do a complete redraw instead.
1081          }          }
1082      } else {      } else {
1083          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
# Line 599  bool DimRegionChooser::is_in_resize_zone Line 1113  bool DimRegionChooser::is_in_resize_zone
1113          int nbZones = region->pDimensionDefinitions[dim].zones;          int nbZones = region->pDimensionDefinitions[dim].zones;
1114    
1115          int c = 0;          int c = 0;
1116          if (dimregno >= 0) {          if (maindimregno >= 0) {
1117              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
1118              c = dimregno & mask; // mask away this dimension              c = maindimregno & mask; // mask away this dimension
1119          }          }
1120          const bool customsplits =          const bool customsplits =
1121              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
# Line 624  bool DimRegionChooser::is_in_resize_zone Line 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    
1146                      int dr = (dimregno >> bitpos) &                      int dr = (maindimregno >> bitpos) &
1147                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);
1148                      resize.selected = dr == iZone ? resize.left :                      resize.selected = dr == iZone ? resize.left :
1149                          dr == iZone + 1 ? resize.right : resize.none;                          dr == iZone + 1 ? resize.right : resize.none;
# Line 665  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 698  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() {    
1226        printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1227        try {
1228            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) {
1276            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1277            msg.run();
1278        } catch (...) {
1279            Glib::ustring txt = _("An unknown exception occurred!");
1280            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1281            msg.run();
1282      }      }
1283        refresh_all();
1284    }
1285    
1286    void DimRegionChooser::delete_dimension_zone() {
1287        printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1288        try {
1289            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) {
1337            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1338            msg.run();
1339        } catch (...) {
1340            Glib::ustring txt = _("An unknown exception occurred!");
1341            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1342            msg.run();
1343        }
1344        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) {
1363        //printf("key down 0x%x\n", key->keyval);
1364        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1365            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) {
1384        //printf("key up 0x%x\n", key->keyval);
1385        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1386            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        // commented out: re-evaluate maindimcase, since it might not been reset from a previous instrument which causes errors if it got different dimension types
1483        //if (maindimcase.empty()) {
1484            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1485            if (maindimcase.empty()) {
1486                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1487                return;
1488            }
1489        //}
1490    
1491        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1492        if (z < 0) z = 0;
1493        if (z >= region->pDimensionDefinitions[focus_line].zones)
1494            z = region->pDimensionDefinitions[focus_line].zones - 1;
1495    
1496        maindimcase[maindimtype] = z;
1497    
1498        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1499        if (!dr) {
1500            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1501            return;
1502        }
1503    
1504        maindimregno = getDimensionRegionIndex(dr);
1505    
1506        if (!add) {
1507            // reset selected dimregion zones
1508            dimzones.clear();
1509        }
1510        for (DimensionCase::const_iterator it = maindimcase.begin();
1511             it != maindimcase.end(); ++it)
1512        {
1513            dimzones[it->first].insert(it->second);
1514        }
1515    
1516        dimregion_selected();
1517    
1518        // disabled: would overwrite dimregno with wrong value
1519        //refresh_all();
1520        // so requesting just a raw repaint instead:
1521        queue_draw();
1522    }
1523    
1524    void DimRegionChooser::select_next_dimension() {
1525        if (!region) return;
1526        focus_line++;
1527        if (focus_line >= region->Dimensions)
1528            focus_line = region->Dimensions - 1;
1529        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1530        queue_draw();
1531    }
1532    
1533    void DimRegionChooser::select_prev_dimension() {
1534        if (!region) return;
1535        focus_line--;
1536        if (focus_line < 0)
1537            focus_line = 0;
1538        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1539        queue_draw();
1540    }
1541    
1542    gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1543        if (!region) return NULL;
1544        return region->pDimensionRegions[maindimregno];
1545  }  }

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

  ViewVC Help
Powered by ViewVC