/[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 1261 by persson, Thu Jul 5 17:12:20 2007 UTC revision 3286 by schoenebeck, Thu Jun 22 10:54:10 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006, 2007 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>
24    #include <cairomm/surface.h>
25  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
26    #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        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  DimRegionChooser::DimRegionChooser()      *isValidZone = true;
71        return dimCase;
72    }
73    
74    DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
75        red("#ff476e"),
76        blue("#4796ff"),
77        black("black"),
78        white("white")
79  {  {
80      // get_window() would return 0 because the Gdk::Window has not yet been realized      // make sure blue hatched pattern pixmap is loaded
81      // So we can only allocate the colors here - the rest will happen in on_realize().      loadBuiltInPix();
82      Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();  
83        // create blue hatched pattern 1
84      black = Gdk::Color("black");      {
85      white = Gdk::Color("white");          const int width = blueHatchedPattern->get_width();
86      red = Gdk::Color("#8070ff");          const int height = blueHatchedPattern->get_height();
87      blue = Gdk::Color("blue");          const int stride = blueHatchedPattern->get_rowstride();
88      green = Gdk::Color("green");  
89            // manually convert from RGBA to ARGB
90      colormap->alloc_color(black);          this->blueHatchedPatternARGB = blueHatchedPattern->copy();
91      colormap->alloc_color(white);          const int pixelSize = stride / width;
92      colormap->alloc_color(red);          const int totalPixels = width * height;
93      colormap->alloc_color(blue);          assert(pixelSize == 4);
94      colormap->alloc_color(green);          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      w = 800;      multiSelectKeyDown = false;
182      set_flags(Gtk::CAN_FOCUS);      primaryKeyDown = false;
183        shiftKeyDown = false;
184        modifybothchannels = modifyalldimregs = modifybothchannels = false;
185        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    
226      for (int i = 0 ; i < 256 ; i++) {      labels_changed = true;
227          dimvalue_from[i] = 0;  
228          dimvalue_to[i] = 1;      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::on_realize()  void DimRegionChooser::setModifyBothChannels(bool b) {
246  {      modifybothchannels = b;
247      // We need to call the base on_realize()      // redraw required parts
248      Gtk::DrawingArea::on_realize();      queue_draw();
249    }
250    
251      // Now we can allocate any additional resources we need  void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
252      Glib::RefPtr<Gdk::Window> window = get_window();      modifyalldimregs = b;
253      gc = Gdk::GC::create(window);      // redraw required parts
254        queue_draw();
255  }  }
256    
257  bool DimRegionChooser::on_expose_event(GdkEventExpose* event)  void DimRegionChooser::setModifyAllRegions(bool b) {
258        modifyallregions = b;
259    
260        actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
261        actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
262    
263        // redraw required parts
264        queue_draw();
265    }
266    
267    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
268    bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
269  {  {
270        double clipx1 = e->area.x;
271        double clipx2 = e->area.x + e->area.width;
272        double clipy1 = e->area.y;
273        double clipy2 = e->area.y + e->area.height;
274    
275        const Cairo::RefPtr<Cairo::Context>& cr =
276            get_window()->create_cairo_context();
277    #else
278    bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
279    {
280        double clipx1, clipx2, clipy1, clipy2;
281        cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
282    #endif
283    
284      if (!region) return true;      if (!region) return true;
285    
286      // This is where we draw on the window      // This is where we draw on the window
287      Glib::RefPtr<Gdk::Window> window = get_window();      int w = get_width();
288      Glib::RefPtr<Pango::Context> context = get_pango_context();      Glib::RefPtr<Pango::Context> context = get_pango_context();
289    
290      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
291        cr->set_line_width(1);
292    
     window->clear();  
   
     // draw labels on the left (reflecting the dimension type)  
293      int y = 0;      int y = 0;
294      double maxwidth = 0;      if (labels_changed || label_width - 10 > clipx1) {
295      for (int i = 0 ; i < region->Dimensions ; i++) {          // draw labels on the left (reflecting the dimension type)
296          int nbZones = region->pDimensionDefinitions[i].zones;          double maxwidth = 0;
297          if (nbZones) {          for (int i = 0 ; i < region->Dimensions ; i++) {
298              const char* dstr;              int nbZones = region->pDimensionDefinitions[i].zones;
299              char dstrbuf[10];              if (nbZones) {
300              switch (region->pDimensionDefinitions[i].dimension) {                  const char* dstr;
301              case gig::dimension_none: dstr="none"; break;                  char dstrbuf[10];
302              case gig::dimension_samplechannel: dstr="samplechannel"; break;                  switch (region->pDimensionDefinitions[i].dimension) {
303              case gig::dimension_layer: dstr="layer"; break;                  case gig::dimension_none: dstr=_("none"); break;
304              case gig::dimension_velocity: dstr="velocity"; break;                  case gig::dimension_samplechannel: dstr=_("samplechannel");
305              case gig::dimension_channelaftertouch: dstr="channelaftertouch"; break;                      break;
306              case gig::dimension_releasetrigger: dstr="releasetrigger"; break;                  case gig::dimension_layer: dstr=_("layer"); break;
307              case gig::dimension_keyboard: dstr="keyboard"; break;                  case gig::dimension_velocity: dstr=_("velocity"); break;
308              case gig::dimension_roundrobin: dstr="roundrobin"; break;                  case gig::dimension_channelaftertouch:
309              case gig::dimension_random: dstr="random"; break;                      dstr=_("channelaftertouch"); break;
310              case gig::dimension_smartmidi: dstr="smartmidi"; break;                  case gig::dimension_releasetrigger:
311              case gig::dimension_roundrobinkeyboard: dstr="roundrobinkeyboard"; break;                      dstr=_("releasetrigger"); break;
312              case gig::dimension_modwheel: dstr="modwheel"; break;                  case gig::dimension_keyboard: dstr=_("keyswitching"); break;
313              case gig::dimension_breath: dstr="breath"; break;                  case gig::dimension_roundrobin: dstr=_("roundrobin"); break;
314              case gig::dimension_foot: dstr="foot"; break;                  case gig::dimension_random: dstr=_("random"); break;
315              case gig::dimension_portamentotime: dstr="portamentotime"; break;                  case gig::dimension_smartmidi: dstr=_("smartmidi"); break;
316              case gig::dimension_effect1: dstr="effect1"; break;                  case gig::dimension_roundrobinkeyboard:
317              case gig::dimension_effect2: dstr="effect2"; break;                      dstr=_("roundrobinkeyboard"); break;
318              case gig::dimension_genpurpose1: dstr="genpurpose1"; break;                  case gig::dimension_modwheel: dstr=_("modwheel"); break;
319              case gig::dimension_genpurpose2: dstr="genpurpose2"; break;                  case gig::dimension_breath: dstr=_("breath"); break;
320              case gig::dimension_genpurpose3: dstr="genpurpose3"; break;                  case gig::dimension_foot: dstr=_("foot"); break;
321              case gig::dimension_genpurpose4: dstr="genpurpose4"; break;                  case gig::dimension_portamentotime:
322              case gig::dimension_sustainpedal: dstr="sustainpedal"; break;                      dstr=_("portamentotime"); break;
323              case gig::dimension_portamento: dstr="portamento"; break;                  case gig::dimension_effect1: dstr=_("effect1"); break;
324              case gig::dimension_sostenutopedal: dstr="sostenutopedal"; break;                  case gig::dimension_effect2: dstr=_("effect2"); break;
325              case gig::dimension_softpedal: dstr="softpedal"; break;                  case gig::dimension_genpurpose1: dstr=_("genpurpose1"); break;
326              case gig::dimension_genpurpose5: dstr="genpurpose5"; break;                  case gig::dimension_genpurpose2: dstr=_("genpurpose2"); break;
327              case gig::dimension_genpurpose6: dstr="genpurpose6"; break;                  case gig::dimension_genpurpose3: dstr=_("genpurpose3"); break;
328              case gig::dimension_genpurpose7: dstr="genpurpose7"; break;                  case gig::dimension_genpurpose4: dstr=_("genpurpose4"); break;
329              case gig::dimension_genpurpose8: dstr="genpurpose8"; break;                  case gig::dimension_sustainpedal:
330              case gig::dimension_effect1depth: dstr="effect1depth"; break;                      dstr=_("sustainpedal"); break;
331              case gig::dimension_effect2depth: dstr="effect2depth"; break;                  case gig::dimension_portamento: dstr=_("portamento"); break;
332              case gig::dimension_effect3depth: dstr="effect3depth"; break;                  case gig::dimension_sostenutopedal:
333              case gig::dimension_effect4depth: dstr="effect4depth"; break;                      dstr=_("sostenutopedal"); break;
334              case gig::dimension_effect5depth: dstr="effect5depth"; break;                  case gig::dimension_softpedal: dstr=_("softpedal"); break;
335              default:                  case gig::dimension_genpurpose5: dstr=_("genpurpose5"); break;
336                  sprintf(dstrbuf, "%d",                  case gig::dimension_genpurpose6: dstr=_("genpurpose6"); break;
337                          region->pDimensionDefinitions[i].dimension);                  case gig::dimension_genpurpose7: dstr=_("genpurpose7"); break;
338                  dstr = dstrbuf;                  case gig::dimension_genpurpose8: dstr=_("genpurpose8"); break;
339                  break;                  case gig::dimension_effect1depth:
340              }                      dstr=_("effect1depth"); break;
341              layout->set_text(dstr);                  case gig::dimension_effect2depth:
342                        dstr=_("effect2depth"); break;
343              Pango::Rectangle rectangle = layout->get_logical_extents();                  case gig::dimension_effect3depth:
344              double text_w = double(rectangle.get_width()) / Pango::SCALE;                      dstr=_("effect3depth"); break;
345              if (text_w > maxwidth) maxwidth = text_w;                  case gig::dimension_effect4depth:
346              double text_h = double(rectangle.get_height()) / Pango::SCALE;                      dstr=_("effect4depth"); break;
347              Glib::RefPtr<const Gdk::GC> fg = get_style()->get_fg_gc(get_state());                  case gig::dimension_effect5depth:
348              window->draw_layout(fg, 4, int(y + (h - text_h) / 2 + 0.5), layout);                      dstr=_("effect5depth"); break;
349                    default:
350                        sprintf(dstrbuf, "%d",
351                                region->pDimensionDefinitions[i].dimension);
352                        dstr = dstrbuf;
353                        break;
354                    }
355    
356                    // Since bold font yields in larger label width, we first always
357                    // set the bold text variant, retrieve its dimensions (as worst
358                    // case dimensions of the label) ...
359                    layout->set_markup("<b>" + Glib::ustring(dstr) + "</b>");
360                    Pango::Rectangle rectangle = layout->get_logical_extents();
361                    // ... and then reset the label to regular font style in case
362                    // the line is not selected. Otherwise the right hand side
363                    // actual dimension zones would jump around on selection change.
364                    bool isSelectedLine = (focus_line == i);
365                    if (!isSelectedLine)
366                        layout->set_markup(dstr);
367    
368                    double text_w = double(rectangle.get_width()) / Pango::SCALE;
369                    if (text_w > maxwidth) maxwidth = text_w;
370    
371                    if (y + h > clipy1 && y < clipy2 && text_w >= clipx1) {
372                        double text_h = double(rectangle.get_height()) /
373                            Pango::SCALE;
374    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
375                        const Gdk::Color fg = get_style()->get_fg(get_state());
376    #else
377                        const Gdk::RGBA fg =
378                            get_style_context()->get_color(get_state_flags());
379    #endif
380                        Gdk::Cairo::set_source_rgba(cr, fg);
381                        cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));
382    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
383                        pango_cairo_show_layout(cr->cobj(), layout->gobj());
384    #else
385                        layout->show_in_cairo_context(cr);
386    #endif
387                    }
388                }
389                y += h;
390          }          }
391          y += h;          label_width = int(maxwidth + 10);
392            labels_changed = false;
393      }      }
394        if (label_width >= clipx2) return true;
395    
396      // draw dimensions' zones areas      // draw dimensions' zones areas
397      y = 0;      y = 0;
398      int bitpos = 0;      int bitpos = 0;
     label_width = int(maxwidth + 10);  
399      for (int i = 0 ; i < region->Dimensions ; i++) {      for (int i = 0 ; i < region->Dimensions ; i++) {
400          int nbZones = region->pDimensionDefinitions[i].zones;          int nbZones = region->pDimensionDefinitions[i].zones;
401          if (nbZones) {          if (nbZones) {
402              // draw focus rectangle around dimension's label and zones              const gig::dimension_t dimension = region->pDimensionDefinitions[i].dimension;
             if (has_focus() && focus_line == i) {  
                 Gdk::Rectangle farea(0, y, 150, 20);  
                 get_style()->paint_focus(window, get_state(), farea, *this, "",  
                                          0, y, label_width, 20);  
             }  
   
             Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();  
             // draw top and bottom lines of dimension's zones  
             window->draw_line(black, label_width, y, w - 1, y);  
             window->draw_line(black, w - 1, y + h - 1, label_width, y + h - 1);  
             // erase whole dimension's zones area  
             window->draw_rectangle(get_style()->get_white_gc(), true,  
                                    label_width + 1, y + 1, (w - label_width - 2), h - 2);  
   
             int c = 0;  
             if (dimregno >= 0) {  
                 int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);  
                 c = dimregno & mask; // mask away this dimension  
             }  
             bool customsplits =  
                 ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&  
                  region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||  
                 (region->pDimensionDefinitions[i].dimension == gig::dimension_velocity &&  
                  region->pDimensionRegions[c]->VelocityUpperLimit));  
403    
404              // draw dimension's zone borders              if (y >= clipy2) break;
405              if (customsplits) {              if (y + h > clipy1) {
406                  window->draw_line(black, label_width, y + 1, label_width, y + h - 2);                  // draw focus rectangle around dimension's label and zones
407                  for (int j = 0 ; j < nbZones ; j++) {                  if (has_focus() && focus_line == i) {
408                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
409                      int upperLimit = d->DimensionUpperLimits[i];                      Gdk::Rectangle farea(0, y, 150, h);
410                      if (!upperLimit) upperLimit = d->VelocityUpperLimit;                      get_style()->paint_focus(get_window(), get_state(), farea,
411                      int v = upperLimit + 1;                                               *this, "",
412                      int x = int((w - label_width - 1) * v / 128.0 + 0.5);                                               0, y, label_width, h);
413                      window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);  #else
414                        get_style_context()->render_focus(cr,
415                                                          0, y, label_width, h);
416    #endif
417                  }                  }
418              } else {  
419                  for (int j = 0 ; j <= nbZones ; j++) {                  // draw top and bottom lines of dimension's zones
420                      int x = int((w - label_width - 1) * j / double(nbZones) + 0.5);                  Gdk::Cairo::set_source_rgba(cr, black);
421                      window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);                  cr->move_to(label_width, y + 0.5);
422                    cr->line_to(w, y + 0.5);
423                    cr->move_to(w, y + h - 0.5);
424                    cr->line_to(label_width, y + h - 0.5);
425                    cr->stroke();
426    
427                    // erase whole dimension's zones area
428                    Gdk::Cairo::set_source_rgba(cr, white);
429                    cr->rectangle(label_width + 1, y + 1,
430                                  (w - label_width - 2), h - 2);
431                    cr->fill();
432    
433                    int c = 0;
434                    if (maindimregno >= 0) {
435                        int mask =
436                            ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
437                              bitpos);
438                        c = maindimregno & mask; // mask away this dimension
439                  }                  }
440              }                  bool customsplits =
441                        ((region->pDimensionDefinitions[i].split_type ==
442                          gig::split_type_normal &&
443                          region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
444                         (region->pDimensionDefinitions[i].dimension ==
445                          gig::dimension_velocity &&
446                          region->pDimensionRegions[c]->VelocityUpperLimit));
447    
448              // draw fill for currently selected zone                  // draw dimension zones
449              if (dimregno >= 0) {                  Gdk::Cairo::set_source_rgba(cr, black);
                 gc->set_foreground(red);  
                 int dr = (dimregno >> bitpos) & ((1 << region->pDimensionDefinitions[i].bits) - 1);  
450                  if (customsplits) {                  if (customsplits) {
451                      int x1 = 0;                      cr->move_to(label_width + 0.5, y + 1);
452                        cr->line_to(label_width + 0.5, y + h - 1);
453                        int prevX = label_width;
454                        int prevUpperLimit = -1;
455    
456                      for (int j = 0 ; j < nbZones ; j++) {                      for (int j = 0 ; j < nbZones ; j++) {
457                          gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];                          // draw dimension zone's borders for custom splits
458                            gig::DimensionRegion* d =
459                                region->pDimensionRegions[c + (j << bitpos)];
460                          int upperLimit = d->DimensionUpperLimits[i];                          int upperLimit = d->DimensionUpperLimits[i];
461                          if (!upperLimit) upperLimit = d->VelocityUpperLimit;                          if (!upperLimit) upperLimit = d->VelocityUpperLimit;
462                          int v = upperLimit + 1;                          int v = upperLimit + 1;
463                          int x2 = int((w - label_width - 1) * v / 128.0 + 0.5);                          int x = int((w - label_width - 1) * v / 128.0 + 0.5) +
464                          if (j == dr && x1 < x2) {                              label_width;
465                              window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,                          if (x >= clipx2) break;
466                                                     (x2 - x1) - 1, h - 2);                          if (x < clipx1) continue;
467                              break;                          Gdk::Cairo::set_source_rgba(cr, black);
468                            cr->move_to(x + 0.5, y + 1);
469                            cr->line_to(x + 0.5, y + h - 1);
470                            cr->stroke();
471    
472                            // draw fill for zone
473                            bool isSelectedZone = this->dimzones[dimension].count(j);
474                            bool isMainSelection =
475                                this->maindimcase.find(dimension) != this->maindimcase.end() &&
476                                this->maindimcase[dimension] == j;
477                            bool isCheckBoxSelected =
478                                modifyalldimregs ||
479                                (modifybothchannels &&
480                                    dimension == gig::dimension_samplechannel);
481                            if (isMainSelection)
482                                Gdk::Cairo::set_source_rgba(cr, blue);
483                            else if (isSelectedZone)
484                                cr->set_source(blueHatchedSurfacePattern2);
485                            else if (isCheckBoxSelected)
486                                cr->set_source(blueHatchedSurfacePattern);
487                            else
488                                Gdk::Cairo::set_source_rgba(cr, white);
489    
490                            cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
491                            cr->fill();
492    
493                            // draw text showing the beginning of the dimension zone
494                            // as numeric value to the user
495                            {
496                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
497                                layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
498                                Gdk::Cairo::set_source_rgba(cr, black);
499                                // get the text dimensions
500                                int text_width, text_height;
501                                layout->get_pixel_size(text_width, text_height);
502                                // move text to the left end of the dimension zone
503                                cr->move_to(prevX + 3, y + (h - text_height) / 2);
504    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
505                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
506    #else
507                                layout->show_in_cairo_context(cr);
508    #endif
509                            }
510                            // draw text showing the end of the dimension zone
511                            // as numeric value to the user
512                            {
513                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
514                                layout->set_text(Glib::Ascii::dtostr(upperLimit));
515                                Gdk::Cairo::set_source_rgba(cr, black);
516                                // get the text dimensions
517                                int text_width, text_height;
518                                layout->get_pixel_size(text_width, text_height);
519                                // move text to the left end of the dimension zone
520                                cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
521    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
522                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
523    #else
524                                layout->show_in_cairo_context(cr);
525    #endif
526                          }                          }
527                          x1 = x2;  
528                            prevX = x;
529                            prevUpperLimit = upperLimit;
530                      }                      }
531                  } else {                  } else {
532                      if (dr < nbZones) {                      int prevX = 0;
533                          int x1 = int((w - label_width - 1) * dr / double(nbZones) + 0.5);                      for (int j = 0 ; j <= nbZones ; j++) {
534                          int x2 = int((w - label_width - 1) * (dr + 1) / double(nbZones) + 0.5);                          // draw dimension zone's borders for normal splits
535                          window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,                          int x = int((w - label_width - 1) * j /
536                                                 (x2 - x1) - 1, h - 2);                                      double(nbZones) + 0.5) + label_width;
537                      }                          if (x >= clipx2) break;
538                            if (x < clipx1) continue;
539                            Gdk::Cairo::set_source_rgba(cr, black);
540                            cr->move_to(x + 0.5, y + 1);
541                            cr->line_to(x + 0.5, y + h - 1);
542                            cr->stroke();
543    
544                            if (j != 0) {
545                                // draw fill for zone
546                                bool isSelectedZone = this->dimzones[dimension].count(j-1);
547                                bool isMainSelection =
548                                    this->maindimcase.find(dimension) != this->maindimcase.end() &&
549                                    this->maindimcase[dimension] == (j-1);
550                                bool isCheckBoxSelected =
551                                    modifyalldimregs ||
552                                    (modifybothchannels &&
553                                        dimension == gig::dimension_samplechannel);
554                                if (isMainSelection)
555                                    Gdk::Cairo::set_source_rgba(cr, blue);
556                                else if (isSelectedZone)
557                                    cr->set_source(blueHatchedSurfacePattern2);
558                                else if (isCheckBoxSelected)
559                                    cr->set_source(blueHatchedSurfacePattern);
560                                else
561                                    Gdk::Cairo::set_source_rgba(cr, white);
562                                cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
563                                cr->fill();
564    
565                                // draw text showing the beginning of the dimension zone
566                                // as numeric value to the user
567                                {
568                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
569                                    layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
570                                    Gdk::Cairo::set_source_rgba(cr, black);
571                                    // get the text dimensions
572                                    int text_width, text_height;
573                                    layout->get_pixel_size(text_width, text_height);
574                                    // move text to the left end of the dimension zone
575                                    cr->move_to(prevX + 3, y + (h - text_height) / 2);
576    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
577                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
578    #else
579                                    layout->show_in_cairo_context(cr);
580    #endif
581                                }
582                                // draw text showing the end of the dimension zone
583                                // as numeric value to the user
584                                {
585                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
586                                    layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
587                                    Gdk::Cairo::set_source_rgba(cr, black);
588                                    // get the text dimensions
589                                    int text_width, text_height;
590                                    layout->get_pixel_size(text_width, text_height);
591                                    // move text to the left end of the dimension zone
592                                    cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
593    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
594                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
595    #else
596                                    layout->show_in_cairo_context(cr);
597    #endif
598                                }
599                            }
600                            prevX = x;
601                        }      
602                  }                  }
603              }              }
   
604              y += h;              y += h;
605          }          }
606          bitpos += region->pDimensionDefinitions[i].bits;          bitpos += region->pDimensionDefinitions[i].bits;
# Line 231  bool DimRegionChooser::on_expose_event(G Line 609  bool DimRegionChooser::on_expose_event(G
609      return true;      return true;
610  }  }
611    
 void DimRegionChooser::on_size_request(GtkRequisition* requisition)  
 {  
     printf("DimRegionChooser::on_size_request\n");  
     *requisition = GtkRequisition();  
     requisition->height = region ? nbDimensions * 20 : 0;  
     requisition->width = 800;  
 }  
   
612  void DimRegionChooser::set_region(gig::Region* region)  void DimRegionChooser::set_region(gig::Region* region)
613  {  {
614      this->region = region;      this->region = region;
615      dimregno = 0;      maindimregno = 0;
616      nbDimensions = 0;      nbDimensions = 0;
617      if (region) {      if (region) {
618          int bitcount = 0;          int bitcount = 0;
# Line 250  void DimRegionChooser::set_region(gig::R Line 620  void DimRegionChooser::set_region(gig::R
620              if (region->pDimensionDefinitions[dim].bits == 0) continue;              if (region->pDimensionDefinitions[dim].bits == 0) continue;
621              nbDimensions++;              nbDimensions++;
622    
623              int from = dimvalue_from[region->pDimensionDefinitions[dim].dimension];              int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
624              int to = dimvalue_to[region->pDimensionDefinitions[dim].dimension];                               region->pDimensionDefinitions[dim].zones - 1);
625              int z;              maindimregno |= (z << bitcount);
             switch (region->pDimensionDefinitions[dim].split_type) {  
             case gig::split_type_normal:  
                 z = int((to + from) / 2.0 / region->pDimensionDefinitions[dim].zone_size);  
                 break;  
             case gig::split_type_bit:  
                 z = std::min(from, region->pDimensionDefinitions[dim].zones - 1);  
                 break;  
             }  
             int mask =  
                 ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) <<  
                   bitcount);  
             dimregno &= mask;  
             dimregno |= (z << bitcount);  
626              bitcount += region->pDimensionDefinitions[dim].bits;              bitcount += region->pDimensionDefinitions[dim].bits;
627          }          }
         dimreg = region->pDimensionRegions[dimregno];  
     } else {  
         dimreg = 0;  
628      }      }
629      dimregion_selected();      dimregion_selected();
630        set_size_request(800, region ? nbDimensions * h : 0);
631    
632        labels_changed = true;
633      queue_resize();      queue_resize();
634        queue_draw();
635  }  }
636    
637  bool DimRegionChooser::on_button_release_event(GdkEventButton* event)  void DimRegionChooser::refresh_all() {
638        set_region(region);
639    }
640    
641    void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
642                                          std::set<gig::DimensionRegion*>& dimregs) const
643  {  {
644      if (resize.active) {      for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
645          get_window()->pointer_ungrab(event->time);          gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
646          resize.active = false;          if (!dimRgn) continue;
647            bool isValidZone;
648            std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
649            if (!isValidZone) continue;
650            for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
651                 it != dimCase.end(); ++it)
652            {
653                if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
654    
655                std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
656                    this->dimzones.find(it->first);
657                if (itSelectedDimension != this->dimzones.end() &&
658                    itSelectedDimension->second.count(it->second)) continue; // is selected
659    
660                goto notSelected;
661            }
662    
663          if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {          dimregs.insert(dimRgn);
664    
665              int bitpos = 0;          notSelected:
666              for (int j = 0 ; j < resize.dimension ; j++) {          ;
667                  bitpos += region->pDimensionDefinitions[j].bits;      }
668    }
669    
670    void DimRegionChooser::update_after_resize()
671    {
672        const uint8_t upperLimit = resize.pos - 1;
673        gig::Instrument* instr = (gig::Instrument*)region->GetParent();
674    
675        int bitpos = 0;
676        for (int j = 0 ; j < resize.dimension ; j++) {
677            bitpos += region->pDimensionDefinitions[j].bits;
678        }
679    
680        const int stereobitpos =
681            (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
682    
683        // the velocity dimension must be handled differently than all other
684        // dimension types, because
685        // 1. it is currently the only dimension type which allows different zone
686        //    sizes for different cases
687        // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
688        if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
689            int mask =
690                ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
691            int c = maindimregno & mask; // mask away this dimension
692    
693            if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
694                // the velocity dimension didn't previously have
695                // custom v3 splits, so we initialize all splits with
696                // default values
697                int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
698                for (int j = 0 ; j < nbZones ; j++) {
699                    gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
700                    d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
701              }              }
702              int mask =          }
703                  ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);          if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {
704              int c = dimregno & mask; // mask away this dimension              // the velocity dimension didn't previously have
705                // custom v2 splits, so we initialize all splits with
706              if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {              // default values
707                  // the velocity dimension didn't previously have              int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
708                  // custom v3 splits, so we initialize all splits with              for (int j = 0 ; j < nbZones ; j++) {
709                  // default values                  gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
710                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);
711                  for (int j = 0 ; j < nbZones ; j++) {              }
712                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];          }
713                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);  
714            int index = c + (resize.zone << bitpos);
715            gig::DimensionRegion* d = region->pDimensionRegions[index];
716            // update both v2 and v3 values
717            d->DimensionUpperLimits[resize.dimension] = upperLimit;
718            d->VelocityUpperLimit = upperLimit;
719            if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
720                gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
721                d->DimensionUpperLimits[resize.dimension] = upperLimit;
722                d->VelocityUpperLimit = upperLimit;
723            }
724    
725            if (modifyalldimregs) {
726                gig::Region* rgn = NULL;
727                for (int key = 0; key < 128; ++key) {
728                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
729                    rgn = instr->GetRegion(key);
730                    if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
731                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
732                    if (!dimdef) continue;
733                    if (dimdef->zones != resize.dimensionDef.zones) continue;
734                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
735                    assert(iDim >= 0 && iDim < rgn->Dimensions);
736    
737                    // the dimension layout might be completely different in this
738                    // region, so we have to recalculate bitpos etc for this region
739                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
740                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
741                    const int selection = resize.zone << bitpos;
742    
743                    // primitive and inefficient loop implementation, however due to
744                    // this circumstance the loop code is much simpler, and its lack
745                    // of runtime efficiency should not be notable in practice
746                    for (int idr = 0; idr < 256; ++idr) {
747                        const int index = (idr & stencil) | selection;
748                        assert(index >= 0 && index < 256);
749                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
750                        if (!dr) continue;
751                        dr->DimensionUpperLimits[iDim] = upperLimit;
752                        d->VelocityUpperLimit = upperLimit;
753                  }                  }
754              }              }
755              if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {          } else if (modifyallregions) { // implies modifyalldimregs is false ...
756                  // the velocity dimension didn't previously have              // resolve the precise case we need to modify for all other regions
757                  // custom v2 splits, so we initialize all splits with              DimensionCase dimCase = dimensionCaseOf(d);
758                  // default values              // apply the velocity upper limit change to that resolved dim case
759                // of all regions ...
760                gig::Region* rgn = NULL;
761                for (int key = 0; key < 128; ++key) {
762                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
763                    rgn = instr->GetRegion(key);
764                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
765                    if (!dimdef) continue;
766                    if (dimdef->zones != resize.dimensionDef.zones) continue;
767                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
768                    assert(iDim >= 0 && iDim < rgn->Dimensions);
769    
770                    std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
771                    for (int i = 0; i < dimrgns.size(); ++i) {
772                        gig::DimensionRegion* dr = dimrgns[i];
773                        dr->DimensionUpperLimits[iDim] = upperLimit;
774                        dr->VelocityUpperLimit = upperLimit;
775                    }
776                }
777            }
778        } else {
779            for (int i = 0 ; i < region->DimensionRegions ; ) {
780                if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
781                    // the dimension didn't previously have custom
782                    // limits, so we have to set default limits for
783                    // all the dimension regions
784                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
785    
786                  for (int j = 0 ; j < nbZones ; j++) {                  for (int j = 0 ; j < nbZones ; j++) {
787                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];                      gig::DimensionRegion* d = region->pDimensionRegions[i + (j << bitpos)];
788                      d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
789                  }                  }
790              }              }
791                int index = i + (resize.zone << bitpos);
792              gig::DimensionRegion *d = region->pDimensionRegions[c + resize.offset];              gig::DimensionRegion* d = region->pDimensionRegions[index];
793              // update both v2 and v3 values              d->DimensionUpperLimits[resize.dimension] = upperLimit;
794              d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;  #if 0       // the following is currently not necessary, because ATM the gig format uses for all dimension types except of the veleocity dimension the same zone sizes for all cases
795              d->VelocityUpperLimit = resize.pos - 1;              if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
796                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
797          } else {                  d->DimensionUpperLimits[resize.dimension] = upperLimit;
798              for (int i = 0 ; i < region->DimensionRegions ; ) {              }
799    #endif
800                  if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              int bitpos = 0;
801                      // the dimension didn't previously have custom              int j;
802                      // limits, so we have to set default limits for              for (j = 0 ; j < region->Dimensions ; j++) {
803                      // all the dimension regions                  if (j != resize.dimension) {
804                      int bitpos = 0;                      int maxzones = 1 << region->pDimensionDefinitions[j].bits;
805                      for (int j = 0 ; j < resize.dimension ; j++) {                      int dimj = (i >> bitpos) & (maxzones - 1);
806                          bitpos += region->pDimensionDefinitions[j].bits;                      if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;
                     }  
                     int nbZones = region->pDimensionDefinitions[resize.dimension].zones;  
   
                     for (int j = 0 ; j < nbZones ; j++) {  
                         gig::DimensionRegion *d = region->pDimensionRegions[i + (j << bitpos)];  
                         d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);  
                     }  
807                  }                  }
808                  gig::DimensionRegion *d = region->pDimensionRegions[i + resize.offset];                  bitpos += region->pDimensionDefinitions[j].bits;
809                  d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              }
810                if (j == region->Dimensions) break;
811                i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
812            }
813    
814                  int bitpos = 0;          if (modifyallregions) { // TODO: this code block could be merged with the similar (and more generalized) code block of the velocity dimension above
815                  int j;              gig::Region* rgn = NULL;
816                  for (j = 0 ; j < region->Dimensions ; j++) {              for (int key = 0; key < 128; ++key) {
817                      if (j != resize.dimension) {                  if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
818                          int maxzones = 1 << region->pDimensionDefinitions[j].bits;                  rgn = instr->GetRegion(key);
819                          int dimj = (i >> bitpos) & (maxzones - 1);                  gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
820                          if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;                  if (!dimdef) continue;
821                      }                  if (dimdef->zones != resize.dimensionDef.zones) continue;
822                      bitpos += region->pDimensionDefinitions[j].bits;                  const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
823                    assert(iDim >= 0 && iDim < rgn->Dimensions);
824    
825                    // the dimension layout might be completely different in this
826                    // region, so we have to recalculate bitpos etc for this region
827                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
828                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
829                    const int selection = resize.zone << bitpos;
830    
831                    // this loop implementation is less efficient than the above's
832                    // loop implementation (which skips unnecessary dimension regions)
833                    // however this code is much simpler, and its lack of runtime
834                    // efficiency should not be notable in practice
835                    for (int idr = 0; idr < 256; ++idr) {
836                        const int index = (idr & stencil) | selection;
837                        assert(index >= 0 && index < 256);
838                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
839                        if (!dr) continue;
840                        dr->DimensionUpperLimits[iDim] = upperLimit;
841                  }                  }
                 if (j == region->Dimensions) break;  
                 i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);  
842              }              }
843          }          }
844        }
845    }
846    
847    bool DimRegionChooser::on_button_release_event(GdkEventButton* event)
848    {
849        if (resize.active) {
850    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
851            get_window()->pointer_ungrab(event->time);
852    #else
853            Glib::wrap(event->device, true)->ungrab(event->time);
854    #endif
855            resize.active = false;
856    
857          region_changed();          region_changed();
858    
859          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {          if (!is_in_resize_zone(event->x, event->y) && cursor_is_resize) {
# Line 365  bool DimRegionChooser::on_button_release Line 866  bool DimRegionChooser::on_button_release
866    
867  bool DimRegionChooser::on_button_press_event(GdkEventButton* event)  bool DimRegionChooser::on_button_press_event(GdkEventButton* event)
868  {  {
869        int w = get_width();
870      if (region && event->y < nbDimensions * h &&      if (region && event->y < nbDimensions * h &&
871          event->x >= label_width && event->x < w) {          event->x >= label_width && event->x < w) {
872    
873          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
874              Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
875              get_window()->pointer_grab(false,              get_window()->pointer_grab(false,
876                                         Gdk::BUTTON_RELEASE_MASK |                                         Gdk::BUTTON_RELEASE_MASK |
877                                         Gdk::POINTER_MOTION_MASK |                                         Gdk::POINTER_MOTION_MASK |
878                                         Gdk::POINTER_MOTION_HINT_MASK,                                         Gdk::POINTER_MOTION_HINT_MASK,
879                                         double_arrow, event->time);                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
880                                           event->time);
881    #else
882                Glib::wrap(event->device, true)->grab(get_window(),
883                                                      Gdk::OWNERSHIP_NONE,
884                                                      false,
885                                                      Gdk::BUTTON_RELEASE_MASK |
886                                                      Gdk::POINTER_MOTION_MASK |
887                                                      Gdk::POINTER_MOTION_HINT_MASK,
888                                                      Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
889                                                      event->time);
890    #endif
891              resize.active = true;              resize.active = true;
892          } else {          } else {
893              int ydim = int(event->y / h);              int ydim = int(event->y / h);
# Line 393  bool DimRegionChooser::on_button_press_e Line 906  bool DimRegionChooser::on_button_press_e
906              }              }
907    
908              int i = dim;              int i = dim;
909              if (dimregno < 0) dimregno = 0;              if (maindimregno < 0) maindimregno = 0;
910              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
911              int c = dimregno & mask; // mask away this dimension              int c = this->maindimregno & mask; // mask away this dimension
912    
913              bool customsplits =              bool customsplits =
914                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
# Line 407  bool DimRegionChooser::on_button_press_e Line 920  bool DimRegionChooser::on_button_press_e
920    
921                  if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {                  if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {
922                      for (z = 0 ; z < nbZones ; z++) {                      for (z = 0 ; z < nbZones ; z++) {
923                          gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];                          gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
924                          if (val <= d->DimensionUpperLimits[i]) break;                          if (val <= d->DimensionUpperLimits[i]) break;
925                      }                      }
926                  } else {                  } else {
927                      for (z = 0 ; z < nbZones ; z++) {                      for (z = 0 ; z < nbZones ; z++) {
928                          gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];                          gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
929                          if (val <= d->VelocityUpperLimit) break;                          if (val <= d->VelocityUpperLimit) break;
930                      }                      }
931                  }                  }
# Line 425  bool DimRegionChooser::on_button_press_e Line 938  bool DimRegionChooser::on_button_press_e
938                     region->pDimensionDefinitions[dim].split_type,                     region->pDimensionDefinitions[dim].split_type,
939                     region->pDimensionDefinitions[dim].zones,                     region->pDimensionDefinitions[dim].zones,
940                     region->pDimensionDefinitions[dim].zone_size);                     region->pDimensionDefinitions[dim].zone_size);
941  #if 0              this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
942              switch (region->pDimensionDefinitions[dim].split_type) {              this->maindimregno = c | (z << bitpos);
943              case gig::split_type_normal:              this->maindimtype = region->pDimensionDefinitions[dim].dimension;
944                  dimvalue_from[region->pDimensionDefinitions[dim].dimension] =  
945                      int(z * region->pDimensionDefinitions[dim].zone_size);              if (multiSelectKeyDown) {
946                  dimvalue_to[region->pDimensionDefinitions[dim].dimension] =                  if (dimzones[this->maindimtype].count(z)) {
947                      int((z + 1) * region->pDimensionDefinitions[dim].zone_size) - 1;                      if (dimzones[this->maindimtype].size() > 1) {
948                  break;                          dimzones[this->maindimtype].erase(z);
949              case gig::split_type_bit:                      }
950                  dimvalue_from[region->pDimensionDefinitions[dim].dimension] = z;                  } else {
951                  dimvalue_to[region->pDimensionDefinitions[dim].dimension] = z + 1;                      dimzones[this->maindimtype].insert(z);
952                  break;                  }
953                } else {
954                    this->dimzones.clear();
955                    for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
956                         it != this->maindimcase.end(); ++it)
957                    {
958                        this->dimzones[it->first].insert(it->second);
959                    }
960              }              }
 #endif  
   
             dimregno = c | (z << bitpos);  
961    
962              focus_line = dim;              focus_line = dim;
963              if (has_focus()) queue_draw();              if (has_focus()) queue_draw();
964              else grab_focus();              else grab_focus();
             dimreg = region->pDimensionRegions[dimregno];  
965              dimregion_selected();              dimregion_selected();
966    
967                if (event->button == 3) {
968                    printf("dimregion right click\n");
969                    popup_menu_inside_dimregion->popup(event->button, event->time);
970                }
971    
972                queue_draw();
973          }          }
974      }      }
975      return true;      return true;
# Line 460  bool DimRegionChooser::on_motion_notify_ Line 983  bool DimRegionChooser::on_motion_notify_
983      window->get_pointer(x, y, state);      window->get_pointer(x, y, state);
984    
985      if (resize.active) {      if (resize.active) {
986            int w = get_width();
987          int k = int((x - label_width) * 128.0 / (w - label_width - 1) + 0.5);          int k = int((x - label_width) * 128.0 / (w - label_width - 1) + 0.5);
988    
989          if (k < resize.min) k = resize.min;          if (k < resize.min) k = resize.min;
# Line 468  bool DimRegionChooser::on_motion_notify_ Line 992  bool DimRegionChooser::on_motion_notify_
992          if (k < 2) k = 2; // k is upper limit + 1, upper limit 0 is forbidden          if (k < 2) k = 2; // k is upper limit + 1, upper limit 0 is forbidden
993    
994          if (k != resize.pos) {          if (k != resize.pos) {
             Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();  
             Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();  
   
995              int prevx = int((w - label_width - 1) * resize.pos / 128.0 + 0.5) + label_width;              int prevx = int((w - label_width - 1) * resize.pos / 128.0 + 0.5) + label_width;
996              int x = int((w - label_width - 1) * k / 128.0 + 0.5) + label_width;              int x = int((w - label_width - 1) * k / 128.0 + 0.5) + label_width;
997              int y = resize.dimension * h;              int y = resize.dimension * h;
998                int x1, x2;
999              if (resize.selected == resize.none) {              if (k > resize.pos) {
1000                  if (resize.pos != resize.min && resize.pos != resize.max) {                  x1 = prevx;
1001                      window->draw_line(white, prevx, y + 1, prevx, y + h - 2);                  x2 = x;
                 }  
1002              } else {              } else {
1003                  gc->set_foreground(red);                  x1 = x;
1004                    x2 = prevx;
                 Glib::RefPtr<const Gdk::GC> left;  
                 Glib::RefPtr<const Gdk::GC> right;  
                 if (resize.selected == resize.left) {  
                     left = gc;  
                     right = white;  
                 } else {  
                     left = white;  
                     right = gc;  
                 }  
   
                 if (k > resize.pos) {  
                     int xx = resize.pos == resize.min ? 1 : 0;  
                     window->draw_rectangle(left, true,  
                                            prevx + xx, y + 1, x - prevx - xx, h - 2);  
                 } else {  
                     int xx = resize.pos == resize.max ? 0 : 1;  
                     window->draw_rectangle(right, true,  
                                            x, y + 1, prevx - x + xx, h - 2);  
                 }  
1005              }              }
1006              window->draw_line(black, x, y + 1, x, y + h - 2);              Gdk::Rectangle rect(x1, y + 1, x2 - x1 + 1, h - 2);
1007    
1008              resize.pos = k;              resize.pos = k;
1009                update_after_resize();
1010                get_window()->invalidate_rect(rect, false); // not sufficient ...
1011                queue_draw(); // ... so do a complete redraw instead.
1012          }          }
1013      } else {      } else {
1014          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
1015              if (!cursor_is_resize) {              if (!cursor_is_resize) {
1016                  Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1017                  window->set_cursor(double_arrow);                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
1018    #else
1019                    window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
1020    #endif
1021                  cursor_is_resize = true;                  cursor_is_resize = true;
1022              }              }
1023          } else if (cursor_is_resize) {          } else if (cursor_is_resize) {
# Line 522  bool DimRegionChooser::on_motion_notify_ Line 1030  bool DimRegionChooser::on_motion_notify_
1030    
1031  bool DimRegionChooser::is_in_resize_zone(double x, double y)  bool DimRegionChooser::is_in_resize_zone(double x, double y)
1032  {  {
1033        int w = get_width();
1034      if (region && y < nbDimensions * h && x >= label_width && x < w) {      if (region && y < nbDimensions * h && x >= label_width && x < w) {
1035          int ydim = int(y / h);          int ydim = int(y / h);
1036          int dim;          int dim;
# Line 535  bool DimRegionChooser::is_in_resize_zone Line 1044  bool DimRegionChooser::is_in_resize_zone
1044          int nbZones = region->pDimensionDefinitions[dim].zones;          int nbZones = region->pDimensionDefinitions[dim].zones;
1045    
1046          int c = 0;          int c = 0;
1047          if (dimregno >= 0) {          if (maindimregno >= 0) {
1048              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
1049              c = dimregno & mask; // mask away this dimension              c = maindimregno & mask; // mask away this dimension
1050          }          }
1051          const bool customsplits =          const bool customsplits =
1052              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
# Line 549  bool DimRegionChooser::is_in_resize_zone Line 1058  bool DimRegionChooser::is_in_resize_zone
1058          if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {          if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {
1059              int prev_limit = 0;              int prev_limit = 0;
1060              for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {              for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {
1061                  gig::DimensionRegion *d = region->pDimensionRegions[c + (iZone << bitpos)];                  gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
1062                  const int upperLimit =                  const int upperLimit =
1063                      (customsplits) ?                      (customsplits) ?
1064                          (d->DimensionUpperLimits[dim]) ?                          (d->DimensionUpperLimits[dim]) ?
# Line 560  bool DimRegionChooser::is_in_resize_zone Line 1069  bool DimRegionChooser::is_in_resize_zone
1069                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
1070                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
1071                      resize.dimension = dim;                      resize.dimension = dim;
1072                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
1073                        resize.zone = iZone;
1074                      resize.pos = limit;                      resize.pos = limit;
1075                      resize.min = prev_limit;                      resize.min = prev_limit;
1076    
1077                      int dr = (dimregno >> bitpos) &                      int dr = (maindimregno >> bitpos) &
1078                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);
1079                      resize.selected = dr == iZone ? resize.left :                      resize.selected = dr == iZone ? resize.left :
1080                          dr == iZone + 1 ? resize.right : resize.none;                          dr == iZone + 1 ? resize.right : resize.none;
1081    
1082                      iZone++;                      iZone++;
1083                      gig::DimensionRegion *d = region->pDimensionRegions[c + (iZone << bitpos)];                      gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
1084    
1085                      const int upperLimit =                      const int upperLimit =
1086                          (customsplits) ?                          (customsplits) ?
# Line 589  bool DimRegionChooser::is_in_resize_zone Line 1099  bool DimRegionChooser::is_in_resize_zone
1099      return false;      return false;
1100  }  }
1101    
1102  sigc::signal<void> DimRegionChooser::signal_dimregion_selected()  sigc::signal<void>& DimRegionChooser::signal_dimregion_selected()
1103  {  {
1104      return dimregion_selected;      return dimregion_selected;
1105  }  }
1106    
1107  sigc::signal<void> DimRegionChooser::signal_region_changed()  sigc::signal<void>& DimRegionChooser::signal_region_changed()
1108  {  {
1109      return region_changed;      return region_changed;
1110  }  }
1111    
1112  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
1113  {  {
1114      // TODO: kolla att region finns osv, dvs att det går att sätta      // TODO: check that region exists etc, that is, that it's possible
1115      // fokus.      // to set focus
1116      if (direction == Gtk::DIR_TAB_FORWARD ||      if (direction == Gtk::DIR_TAB_FORWARD ||
1117          direction == Gtk::DIR_DOWN) {          direction == Gtk::DIR_DOWN) {
1118          if (!has_focus()) {          if (!has_focus()) {
# Line 634  bool DimRegionChooser::on_focus(Gtk::Dir Line 1144  bool DimRegionChooser::on_focus(Gtk::Dir
1144              }              }
1145          }          }
1146      } else if (!has_focus()) {      } else if (!has_focus()) {
1147          // TODO: kolla att focus_line finns!          // TODO: check that focus_line exists
1148          grab_focus();          grab_focus();
1149          return true;          return true;
1150      } else {      } else {
1151          // TODO: öka eller minska värde!          // TODO: increase or decrease value
1152        }
1153        return false;
1154    }
1155    
1156    void DimRegionChooser::split_dimension_zone() {    
1157        printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1158        try {
1159            if (!modifyallregions) {
1160                region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1161            } else {
1162                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1163                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1164                assert(pMaindimdef != NULL);
1165                // retain structure by value since the original region will be
1166                // modified in the loop below as well
1167                gig::dimension_def_t maindimdef = *pMaindimdef;
1168                std::vector<gig::Region*> ignoredAll;
1169                std::vector<gig::Region*> ignoredMinor;
1170                std::vector<gig::Region*> ignoredCritical;
1171                gig::Region* rgn = NULL;
1172                for (int key = 0; key < 128; ++key) {
1173                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1174                    rgn = instr->GetRegion(key);
1175    
1176                    // ignore all regions which do not exactly match the dimension
1177                    // layout of the selected region where this operation was emitted
1178                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1179                    if (!dimdef) {
1180                        ignoredAll.push_back(rgn);
1181                        ignoredMinor.push_back(rgn);
1182                        continue;
1183                    }
1184                    if (dimdef->zones != maindimdef.zones) {
1185                        ignoredAll.push_back(rgn);
1186                        ignoredCritical.push_back(rgn);
1187                        continue;
1188                    }
1189    
1190                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1191                }
1192                if (!ignoredAll.empty()) {
1193                    Glib::ustring txt;
1194                    if (ignoredCritical.empty())
1195                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1196                    else if (ignoredMinor.empty())
1197                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1198                    else
1199                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1200                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1201                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1202                    Gtk::MessageDialog msg(txt, false, type);
1203                    msg.run();
1204                }
1205            }
1206        } catch (RIFF::Exception e) {
1207            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1208            msg.run();
1209        } catch (...) {
1210            Glib::ustring txt = _("An unknown exception occurred!");
1211            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1212            msg.run();
1213      }      }
1214        refresh_all();
1215    }
1216    
1217    void DimRegionChooser::delete_dimension_zone() {
1218        printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1219        try {
1220            if (!modifyallregions) {
1221                region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1222            } else {
1223                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1224                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1225                assert(pMaindimdef != NULL);
1226                // retain structure by value since the original region will be
1227                // modified in the loop below as well
1228                gig::dimension_def_t maindimdef = *pMaindimdef;
1229                std::vector<gig::Region*> ignoredAll;
1230                std::vector<gig::Region*> ignoredMinor;
1231                std::vector<gig::Region*> ignoredCritical;
1232                gig::Region* rgn = NULL;
1233                for (int key = 0; key < 128; ++key) {
1234                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1235                    rgn = instr->GetRegion(key);
1236    
1237                    // ignore all regions which do not exactly match the dimension
1238                    // layout of the selected region where this operation was emitted
1239                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1240                    if (!dimdef) {
1241                        ignoredAll.push_back(rgn);
1242                        ignoredMinor.push_back(rgn);
1243                        continue;
1244                    }
1245                    if (dimdef->zones != maindimdef.zones) {
1246                        ignoredAll.push_back(rgn);
1247                        ignoredCritical.push_back(rgn);
1248                        continue;
1249                    }
1250    
1251                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1252                }
1253                if (!ignoredAll.empty()) {
1254                    Glib::ustring txt;
1255                    if (ignoredCritical.empty())
1256                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1257                    else if (ignoredMinor.empty())
1258                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1259                    else
1260                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1261                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1262                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1263                    Gtk::MessageDialog msg(txt, false, type);
1264                    msg.run();
1265                }
1266            }
1267        } catch (RIFF::Exception e) {
1268            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1269            msg.run();
1270        } catch (...) {
1271            Glib::ustring txt = _("An unknown exception occurred!");
1272            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1273            msg.run();
1274        }
1275        refresh_all();
1276    }
1277    
1278    // Cmd key on Mac, Ctrl key on all other OSs
1279    static const guint primaryKeyL =
1280        #if defined(__APPLE__)
1281        GDK_KEY_Meta_L;
1282        #else
1283        GDK_KEY_Control_L;
1284        #endif
1285    
1286    static const guint primaryKeyR =
1287        #if defined(__APPLE__)
1288        GDK_KEY_Meta_R;
1289        #else
1290        GDK_KEY_Control_R;
1291        #endif
1292    
1293    bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1294        //printf("key down 0x%x\n", key->keyval);
1295        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1296            multiSelectKeyDown = true;
1297        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1298            primaryKeyDown = true;
1299        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1300            shiftKeyDown = true;
1301    
1302        //FIXME: hmm, for some reason GDKMM does not fire arrow key down events, so we are doing those handlers in the key up handler instead for now
1303        /*if (key->keyval == GDK_KEY_Left)
1304            select_prev_dimzone();
1305        if (key->keyval == GDK_KEY_Right)
1306            select_next_dimzone();
1307        if (key->keyval == GDK_KEY_Up)
1308            select_prev_dimension();
1309        if (key->keyval == GDK_KEY_Down)
1310            select_next_dimension();*/
1311        return false;
1312    }
1313    
1314    bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1315        //printf("key up 0x%x\n", key->keyval);
1316        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1317            multiSelectKeyDown = false;
1318        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1319            primaryKeyDown = false;
1320        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1321            shiftKeyDown = false;
1322    
1323        if (!has_focus()) return false;
1324    
1325        // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow
1326        // (which is supposed to switch between regions)
1327        if (primaryKeyDown) return false;
1328    
1329        // avoid conflict with Alt+Shift+Left and Alt+Shift+Right accelerators on
1330        // mainwindow
1331        if (shiftKeyDown) return false;
1332    
1333        if (key->keyval == GDK_KEY_Left)
1334            select_prev_dimzone();
1335        if (key->keyval == GDK_KEY_Right)
1336            select_next_dimzone();
1337        if (key->keyval == GDK_KEY_Up)
1338            select_prev_dimension();
1339        if (key->keyval == GDK_KEY_Down)
1340            select_next_dimension();
1341    
1342        return false;
1343    }
1344    
1345    void DimRegionChooser::resetSelectedZones() {
1346        this->dimzones.clear();
1347        if (!region) {
1348            queue_draw(); // redraw required parts
1349            return;
1350        }
1351        if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1352            queue_draw(); // redraw required parts
1353            return;
1354        }
1355        if (!region->pDimensionRegions[maindimregno]) {
1356            queue_draw(); // redraw required parts
1357            return;
1358        }
1359        gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1360    
1361        bool isValidZone;
1362        this->maindimcase = dimensionCaseOf(dimrgn);
1363    
1364        for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1365             it != this->maindimcase.end(); ++it)
1366        {
1367            this->dimzones[it->first].insert(it->second);
1368        }
1369    
1370        // redraw required parts
1371        queue_draw();
1372    }
1373    
1374    bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1375        if (!region) return false; //.selection failed
1376    
1377        for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1378            if (region->pDimensionRegions[dr] == dimrgn) {
1379                // reset dim region zone selection to the requested specific dim region case
1380                maindimregno = dr;
1381                resetSelectedZones();
1382    
1383                // emit signal that dimregion selection has changed, for external entities
1384                dimregion_selected();
1385    
1386                return true; // selection success
1387            }
1388        }
1389    
1390        return false; //.selection failed
1391    }
1392    
1393    void DimRegionChooser::select_next_dimzone(bool add) {
1394        select_dimzone_by_dir(+1, add);
1395    }
1396    
1397    void DimRegionChooser::select_prev_dimzone(bool add) {
1398        select_dimzone_by_dir(-1, add);
1399    }
1400    
1401    void DimRegionChooser::select_dimzone_by_dir(int dir, bool add) {
1402        if (!region) return;
1403        if (!region->Dimensions) return;
1404        if (focus_line < 0) focus_line = 0;
1405        if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1406    
1407        maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1408        if (maindimtype == gig::dimension_none) {
1409            printf("maindimtype -> none\n");
1410            return;
1411        }
1412    
1413        if (maindimcase.empty()) {
1414            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1415            if (maindimcase.empty()) {
1416                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1417                return;
1418            }
1419        }
1420    
1421        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1422        if (z < 0) z = 0;
1423        if (z >= region->pDimensionDefinitions[focus_line].zones)
1424            z = region->pDimensionDefinitions[focus_line].zones - 1;
1425    
1426        maindimcase[maindimtype] = z;
1427    
1428        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1429        if (!dr) {
1430            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1431            return;
1432        }
1433    
1434        maindimregno = getDimensionRegionIndex(dr);
1435    
1436        if (!add) {
1437            // reset selected dimregion zones
1438            dimzones.clear();
1439        }
1440        for (DimensionCase::const_iterator it = maindimcase.begin();
1441             it != maindimcase.end(); ++it)
1442        {
1443            dimzones[it->first].insert(it->second);
1444        }
1445    
1446        dimregion_selected();
1447    
1448        // disabled: would overwrite dimregno with wrong value
1449        //refresh_all();
1450        // so requesting just a raw repaint instead:
1451        queue_draw();
1452    }
1453    
1454    void DimRegionChooser::select_next_dimension() {
1455        if (!region) return;
1456        focus_line++;
1457        if (focus_line >= region->Dimensions)
1458            focus_line = region->Dimensions - 1;
1459        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1460        queue_draw();
1461    }
1462    
1463    void DimRegionChooser::select_prev_dimension() {
1464        if (!region) return;
1465        focus_line--;
1466        if (focus_line < 0)
1467            focus_line = 0;
1468        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1469        queue_draw();
1470    }
1471    
1472    gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1473        if (!region) return NULL;
1474        return region->pDimensionRegions[maindimregno];
1475  }  }

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

  ViewVC Help
Powered by ViewVC