/[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 1623 by persson, Fri Jan 4 19:42:45 2008 UTC revision 3132 by schoenebeck, Thu Apr 27 17:31:50 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006-2008 Andreas Persson   * Copyright (C) 2006-2017 Andreas Persson
3   *   *
4   * This program is free software; you can redistribute it and/or   * This program is free software; you can redistribute it and/or
5   * modify it under the terms of the GNU General Public License as   * modify it under the terms of the GNU General Public License as
# Line 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
20    #include <gtkmm/box.h>
21  #include "dimregionchooser.h"  #include "dimregionchooser.h"
22    #include <cairomm/context.h>
23    #include <cairomm/surface.h>
24  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
25    #include <gdkmm/general.h>
26    #include <glibmm/stringutils.h>
27    #include <glibmm/ustring.h>
28    #include <gtkmm/messagedialog.h>
29    #include <assert.h>
30    
31    #include "global.h"
32    #include "gfx/builtinpix.h"
33    
34    //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
35    static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
36        DimensionCase dimCase;
37        if (!dr) {
38            *isValidZone = false;
39            return dimCase;
40        }
41    
42        gig::Region* rgn = (gig::Region*) dr->GetParent();
43    
44        // find the dimension region index of the passed dimension region
45        int drIndex;
46        for (drIndex = 0; drIndex < 256; ++drIndex)
47            if (rgn->pDimensionRegions[drIndex] == dr)
48                break;
49    
50        // not found in region, something's horribly wrong
51        if (drIndex == 256) {
52            fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
53            *isValidZone = false;
54            return DimensionCase();
55        }
56    
57        for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
58            const int bits = rgn->pDimensionDefinitions[d].bits;
59            dimCase[rgn->pDimensionDefinitions[d].dimension] =
60                (drIndex >> baseBits) & ((1 << bits) - 1);
61            baseBits += bits;
62            // there are also DimensionRegion objects of unused zones, skip them
63            if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
64                *isValidZone = false;
65                return DimensionCase();
66            }
67        }
68    
69  DimRegionChooser::DimRegionChooser()      *isValidZone = true;
70        return dimCase;
71    }
72    
73    DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
74        red("#ff476e"),
75        blue("#4796ff"),
76        black("black"),
77        white("white")
78  {  {
79      // get_window() would return 0 because the Gdk::Window has not yet been realized      // make sure blue hatched pattern pixmap is loaded
80      // So we can only allocate the colors here - the rest will happen in on_realize().      loadBuiltInPix();
81      Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();  
82        // create blue hatched pattern
83      black = Gdk::Color("black");      {
84      white = Gdk::Color("white");          const int width = blueHatchedPattern->get_width();
85      red = Gdk::Color("#8070ff");          const int height = blueHatchedPattern->get_height();
86      blue = Gdk::Color("blue");          const int stride = blueHatchedPattern->get_rowstride();
87      green = Gdk::Color("green");  
88            // manually convert from RGBA to ARGB
89      colormap->alloc_color(black);          this->blueHatchedPatternARGB = blueHatchedPattern->copy();
90      colormap->alloc_color(white);          const int pixelSize = stride / width;
91      colormap->alloc_color(red);          const int totalPixels = width * height;
92      colormap->alloc_color(blue);          assert(pixelSize == 4);
93      colormap->alloc_color(green);          unsigned char* ptr = this->blueHatchedPatternARGB->get_pixels();
94            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
95                const unsigned char r = ptr[0];
96                const unsigned char g = ptr[1];
97                const unsigned char b = ptr[2];
98                const unsigned char a = ptr[3];
99                ptr[0] = b;
100                ptr[1] = g;
101                ptr[2] = r;
102                ptr[3] = a;
103            }
104    
105            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
106                this->blueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
107            );
108            this->blueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
109            this->blueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
110        }
111    
112      instrument = 0;      instrument = 0;
113      region = 0;      region = 0;
114      dimregno = -1;      maindimregno = -1;
115        maindimtype = gig::dimension_none; // initialize with invalid dimension type
116      focus_line = 0;      focus_line = 0;
117      resize.active = false;      resize.active = false;
118      cursor_is_resize = false;      cursor_is_resize = false;
119      h = 20;      h = 24;
120      set_flags(Gtk::CAN_FOCUS);      multiSelectKeyDown = false;
121        primaryKeyDown = false;
122        shiftKeyDown = false;
123        modifybothchannels = modifyalldimregs = modifybothchannels = false;
124        set_can_focus();
125    
126        const Glib::ustring txtUseCheckBoxAllRegions =
127            _("Use checkbox 'all regions' to control whether this should apply to all regions.");
128    
129        actionGroup = Gtk::ActionGroup::create();
130        actionSplitDimZone = Gtk::Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
131        actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
132        actionGroup->add(
133            actionSplitDimZone,
134            sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
135        );
136        actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
137        actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
138        actionGroup->add(
139            actionDeleteDimZone,
140            sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
141        );
142    
143        uiManager = Gtk::UIManager::create();
144        uiManager->insert_action_group(actionGroup);
145        Glib::ustring ui_info =
146            "<ui>"
147            "  <popup name='PopupMenuInsideDimRegion'>"
148            "    <menuitem action='SplitDimZone'/>"
149            "    <menuitem action='DeleteDimZone'/>"
150            "  </popup>"
151    //         "  <popup name='PopupMenuOutsideDimRegion'>"
152    //         "    <menuitem action='Add'/>"
153    //         "  </popup>"
154            "</ui>";
155        uiManager->add_ui_from_string(ui_info);
156    
157        popup_menu_inside_dimregion = dynamic_cast<Gtk::Menu*>(
158            uiManager->get_widget("/PopupMenuInsideDimRegion"));
159    //     popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(
160    //         uiManager->get_widget("/PopupMenuOutsideDimRegion"));
161    
162      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
163                 Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_HINT_MASK);
164    
165      for (int i = 0 ; i < 256 ; i++) dimvalue[i] = 0;      labels_changed = true;
166    
167        set_tooltip_text(_(
168            "Right click here for options on altering dimension zones. Press and "
169            "hold CTRL key for selecting multiple dimension zones simultaniously."
170        ));
171        
172        window.signal_key_press_event().connect(
173            sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)
174        );
175        window.signal_key_release_event().connect(
176            sigc::mem_fun(*this, &DimRegionChooser::onKeyReleased)
177        );
178  }  }
179    
180  DimRegionChooser::~DimRegionChooser()  DimRegionChooser::~DimRegionChooser()
181  {  {
182  }  }
183    
184  void DimRegionChooser::on_realize()  void DimRegionChooser::setModifyBothChannels(bool b) {
185  {      modifybothchannels = b;
186      // We need to call the base on_realize()  }
     Gtk::DrawingArea::on_realize();  
187    
188      // Now we can allocate any additional resources we need  void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
189      Glib::RefPtr<Gdk::Window> window = get_window();      modifyalldimregs = b;
     gc = Gdk::GC::create(window);  
190  }  }
191    
192  bool DimRegionChooser::on_expose_event(GdkEventExpose* event)  void DimRegionChooser::setModifyAllRegions(bool b) {
193        modifyallregions = b;
194    
195        actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
196        actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
197    }
198    
199    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
200    bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
201  {  {
202        double clipx1 = e->area.x;
203        double clipx2 = e->area.x + e->area.width;
204        double clipy1 = e->area.y;
205        double clipy2 = e->area.y + e->area.height;
206    
207        const Cairo::RefPtr<Cairo::Context>& cr =
208            get_window()->create_cairo_context();
209    #else
210    bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
211    {
212        double clipx1, clipx2, clipy1, clipy2;
213        cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
214    #endif
215    
216      if (!region) return true;      if (!region) return true;
217    
218      // This is where we draw on the window      // This is where we draw on the window
219      int w = get_width();      int w = get_width();
     Glib::RefPtr<Gdk::Window> window = get_window();  
220      Glib::RefPtr<Pango::Context> context = get_pango_context();      Glib::RefPtr<Pango::Context> context = get_pango_context();
221    
222      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
223        cr->set_line_width(1);
224    
     window->clear();  
   
     // draw labels on the left (reflecting the dimension type)  
225      int y = 0;      int y = 0;
226      double maxwidth = 0;      if (labels_changed || label_width - 10 > clipx1) {
227      for (int i = 0 ; i < region->Dimensions ; i++) {          // draw labels on the left (reflecting the dimension type)
228          int nbZones = region->pDimensionDefinitions[i].zones;          double maxwidth = 0;
229          if (nbZones) {          for (int i = 0 ; i < region->Dimensions ; i++) {
230              const char* dstr;              int nbZones = region->pDimensionDefinitions[i].zones;
231              char dstrbuf[10];              if (nbZones) {
232              switch (region->pDimensionDefinitions[i].dimension) {                  const char* dstr;
233              case gig::dimension_none: dstr="none"; break;                  char dstrbuf[10];
234              case gig::dimension_samplechannel: dstr="samplechannel"; break;                  switch (region->pDimensionDefinitions[i].dimension) {
235              case gig::dimension_layer: dstr="layer"; break;                  case gig::dimension_none: dstr=_("none"); break;
236              case gig::dimension_velocity: dstr="velocity"; break;                  case gig::dimension_samplechannel: dstr=_("samplechannel");
237              case gig::dimension_channelaftertouch: dstr="channelaftertouch"; break;                      break;
238              case gig::dimension_releasetrigger: dstr="releasetrigger"; break;                  case gig::dimension_layer: dstr=_("layer"); break;
239              case gig::dimension_keyboard: dstr="keyboard"; break;                  case gig::dimension_velocity: dstr=_("velocity"); break;
240              case gig::dimension_roundrobin: dstr="roundrobin"; break;                  case gig::dimension_channelaftertouch:
241              case gig::dimension_random: dstr="random"; break;                      dstr=_("channelaftertouch"); break;
242              case gig::dimension_smartmidi: dstr="smartmidi"; break;                  case gig::dimension_releasetrigger:
243              case gig::dimension_roundrobinkeyboard: dstr="roundrobinkeyboard"; break;                      dstr=_("releasetrigger"); break;
244              case gig::dimension_modwheel: dstr="modwheel"; break;                  case gig::dimension_keyboard: dstr=_("keyswitching"); break;
245              case gig::dimension_breath: dstr="breath"; break;                  case gig::dimension_roundrobin: dstr=_("roundrobin"); break;
246              case gig::dimension_foot: dstr="foot"; break;                  case gig::dimension_random: dstr=_("random"); break;
247              case gig::dimension_portamentotime: dstr="portamentotime"; break;                  case gig::dimension_smartmidi: dstr=_("smartmidi"); break;
248              case gig::dimension_effect1: dstr="effect1"; break;                  case gig::dimension_roundrobinkeyboard:
249              case gig::dimension_effect2: dstr="effect2"; break;                      dstr=_("roundrobinkeyboard"); break;
250              case gig::dimension_genpurpose1: dstr="genpurpose1"; break;                  case gig::dimension_modwheel: dstr=_("modwheel"); break;
251              case gig::dimension_genpurpose2: dstr="genpurpose2"; break;                  case gig::dimension_breath: dstr=_("breath"); break;
252              case gig::dimension_genpurpose3: dstr="genpurpose3"; break;                  case gig::dimension_foot: dstr=_("foot"); break;
253              case gig::dimension_genpurpose4: dstr="genpurpose4"; break;                  case gig::dimension_portamentotime:
254              case gig::dimension_sustainpedal: dstr="sustainpedal"; break;                      dstr=_("portamentotime"); break;
255              case gig::dimension_portamento: dstr="portamento"; break;                  case gig::dimension_effect1: dstr=_("effect1"); break;
256              case gig::dimension_sostenutopedal: dstr="sostenutopedal"; break;                  case gig::dimension_effect2: dstr=_("effect2"); break;
257              case gig::dimension_softpedal: dstr="softpedal"; break;                  case gig::dimension_genpurpose1: dstr=_("genpurpose1"); break;
258              case gig::dimension_genpurpose5: dstr="genpurpose5"; break;                  case gig::dimension_genpurpose2: dstr=_("genpurpose2"); break;
259              case gig::dimension_genpurpose6: dstr="genpurpose6"; break;                  case gig::dimension_genpurpose3: dstr=_("genpurpose3"); break;
260              case gig::dimension_genpurpose7: dstr="genpurpose7"; break;                  case gig::dimension_genpurpose4: dstr=_("genpurpose4"); break;
261              case gig::dimension_genpurpose8: dstr="genpurpose8"; break;                  case gig::dimension_sustainpedal:
262              case gig::dimension_effect1depth: dstr="effect1depth"; break;                      dstr=_("sustainpedal"); break;
263              case gig::dimension_effect2depth: dstr="effect2depth"; break;                  case gig::dimension_portamento: dstr=_("portamento"); break;
264              case gig::dimension_effect3depth: dstr="effect3depth"; break;                  case gig::dimension_sostenutopedal:
265              case gig::dimension_effect4depth: dstr="effect4depth"; break;                      dstr=_("sostenutopedal"); break;
266              case gig::dimension_effect5depth: dstr="effect5depth"; break;                  case gig::dimension_softpedal: dstr=_("softpedal"); break;
267              default:                  case gig::dimension_genpurpose5: dstr=_("genpurpose5"); break;
268                  sprintf(dstrbuf, "%d",                  case gig::dimension_genpurpose6: dstr=_("genpurpose6"); break;
269                          region->pDimensionDefinitions[i].dimension);                  case gig::dimension_genpurpose7: dstr=_("genpurpose7"); break;
270                  dstr = dstrbuf;                  case gig::dimension_genpurpose8: dstr=_("genpurpose8"); break;
271                  break;                  case gig::dimension_effect1depth:
272              }                      dstr=_("effect1depth"); break;
273              layout->set_text(dstr);                  case gig::dimension_effect2depth:
274                        dstr=_("effect2depth"); break;
275              Pango::Rectangle rectangle = layout->get_logical_extents();                  case gig::dimension_effect3depth:
276              double text_w = double(rectangle.get_width()) / Pango::SCALE;                      dstr=_("effect3depth"); break;
277              if (text_w > maxwidth) maxwidth = text_w;                  case gig::dimension_effect4depth:
278              double text_h = double(rectangle.get_height()) / Pango::SCALE;                      dstr=_("effect4depth"); break;
279              Glib::RefPtr<const Gdk::GC> fg = get_style()->get_fg_gc(get_state());                  case gig::dimension_effect5depth:
280              window->draw_layout(fg, 4, int(y + (h - text_h) / 2 + 0.5), layout);                      dstr=_("effect5depth"); break;
281                    default:
282                        sprintf(dstrbuf, "%d",
283                                region->pDimensionDefinitions[i].dimension);
284                        dstr = dstrbuf;
285                        break;
286                    }
287    
288                    // Since bold font yields in larger label width, we first always
289                    // set the bold text variant, retrieve its dimensions (as worst
290                    // case dimensions of the label) ...
291                    layout->set_markup("<b>" + Glib::ustring(dstr) + "</b>");
292                    Pango::Rectangle rectangle = layout->get_logical_extents();
293                    // ... and then reset the label to regular font style in case
294                    // the line is not selected. Otherwise the right hand side
295                    // actual dimension zones would jump around on selection change.
296                    bool isSelectedLine = (focus_line == i);
297                    if (!isSelectedLine)
298                        layout->set_markup(dstr);
299    
300                    double text_w = double(rectangle.get_width()) / Pango::SCALE;
301                    if (text_w > maxwidth) maxwidth = text_w;
302    
303                    if (y + h > clipy1 && y < clipy2 && text_w >= clipx1) {
304                        double text_h = double(rectangle.get_height()) /
305                            Pango::SCALE;
306    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
307                        const Gdk::Color fg = get_style()->get_fg(get_state());
308    #else
309                        const Gdk::RGBA fg =
310                            get_style_context()->get_color(get_state_flags());
311    #endif
312                        Gdk::Cairo::set_source_rgba(cr, fg);
313                        cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));
314    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
315                        pango_cairo_show_layout(cr->cobj(), layout->gobj());
316    #else
317                        layout->show_in_cairo_context(cr);
318    #endif
319                    }
320                }
321                y += h;
322          }          }
323          y += h;          label_width = int(maxwidth + 10);
324            labels_changed = false;
325      }      }
326        if (label_width >= clipx2) return true;
327    
328      // draw dimensions' zones areas      // draw dimensions' zones areas
329      y = 0;      y = 0;
330      int bitpos = 0;      int bitpos = 0;
     label_width = int(maxwidth + 10);  
331      for (int i = 0 ; i < region->Dimensions ; i++) {      for (int i = 0 ; i < region->Dimensions ; i++) {
332          int nbZones = region->pDimensionDefinitions[i].zones;          int nbZones = region->pDimensionDefinitions[i].zones;
333          if (nbZones) {          if (nbZones) {
334              // 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));  
335    
336              // draw dimension's zone borders              if (y >= clipy2) break;
337              if (customsplits) {              if (y + h > clipy1) {
338                  window->draw_line(black, label_width, y + 1, label_width, y + h - 2);                  // draw focus rectangle around dimension's label and zones
339                  for (int j = 0 ; j < nbZones ; j++) {                  if (has_focus() && focus_line == i) {
340                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
341                      int upperLimit = d->DimensionUpperLimits[i];                      Gdk::Rectangle farea(0, y, 150, h);
342                      if (!upperLimit) upperLimit = d->VelocityUpperLimit;                      get_style()->paint_focus(get_window(), get_state(), farea,
343                      int v = upperLimit + 1;                                               *this, "",
344                      int x = int((w - label_width - 1) * v / 128.0 + 0.5);                                               0, y, label_width, h);
345                      window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);  #else
346                        get_style_context()->render_focus(cr,
347                                                          0, y, label_width, h);
348    #endif
349                  }                  }
350              } else {  
351                  for (int j = 0 ; j <= nbZones ; j++) {                  // draw top and bottom lines of dimension's zones
352                      int x = int((w - label_width - 1) * j / double(nbZones) + 0.5);                  Gdk::Cairo::set_source_rgba(cr, black);
353                      window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);                  cr->move_to(label_width, y + 0.5);
354                    cr->line_to(w, y + 0.5);
355                    cr->move_to(w, y + h - 0.5);
356                    cr->line_to(label_width, y + h - 0.5);
357                    cr->stroke();
358    
359                    // erase whole dimension's zones area
360                    Gdk::Cairo::set_source_rgba(cr, white);
361                    cr->rectangle(label_width + 1, y + 1,
362                                  (w - label_width - 2), h - 2);
363                    cr->fill();
364    
365                    int c = 0;
366                    if (maindimregno >= 0) {
367                        int mask =
368                            ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
369                              bitpos);
370                        c = maindimregno & mask; // mask away this dimension
371                  }                  }
372              }                  bool customsplits =
373                        ((region->pDimensionDefinitions[i].split_type ==
374                          gig::split_type_normal &&
375                          region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
376                         (region->pDimensionDefinitions[i].dimension ==
377                          gig::dimension_velocity &&
378                          region->pDimensionRegions[c]->VelocityUpperLimit));
379    
380              // draw fill for currently selected zone                  // draw dimension zones
381              if (dimregno >= 0) {                  Gdk::Cairo::set_source_rgba(cr, black);
                 gc->set_foreground(red);  
                 int dr = (dimregno >> bitpos) & ((1 << region->pDimensionDefinitions[i].bits) - 1);  
382                  if (customsplits) {                  if (customsplits) {
383                      int x1 = 0;                      cr->move_to(label_width + 0.5, y + 1);
384                        cr->line_to(label_width + 0.5, y + h - 1);
385                        int prevX = label_width;
386                        int prevUpperLimit = -1;
387    
388                      for (int j = 0 ; j < nbZones ; j++) {                      for (int j = 0 ; j < nbZones ; j++) {
389                          gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];                          // draw dimension zone's borders for custom splits
390                            gig::DimensionRegion* d =
391                                region->pDimensionRegions[c + (j << bitpos)];
392                          int upperLimit = d->DimensionUpperLimits[i];                          int upperLimit = d->DimensionUpperLimits[i];
393                          if (!upperLimit) upperLimit = d->VelocityUpperLimit;                          if (!upperLimit) upperLimit = d->VelocityUpperLimit;
394                          int v = upperLimit + 1;                          int v = upperLimit + 1;
395                          int x2 = int((w - label_width - 1) * v / 128.0 + 0.5);                          int x = int((w - label_width - 1) * v / 128.0 + 0.5) +
396                          if (j == dr && x1 < x2) {                              label_width;
397                              window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,                          if (x >= clipx2) break;
398                                                     (x2 - x1) - 1, h - 2);                          if (x < clipx1) continue;
399                              break;                          Gdk::Cairo::set_source_rgba(cr, black);
400                            cr->move_to(x + 0.5, y + 1);
401                            cr->line_to(x + 0.5, y + h - 1);
402                            cr->stroke();
403    
404                            // draw fill for zone
405                            bool isSelectedZone = this->dimzones[dimension].count(j);
406                            bool isMainSelection =
407                                this->maindimcase.find(dimension) != this->maindimcase.end() &&
408                                this->maindimcase[dimension] == j;
409                            if (isMainSelection)
410                                Gdk::Cairo::set_source_rgba(cr, blue);
411                            else if (isSelectedZone)
412                                cr->set_source(blueHatchedSurfacePattern);
413                            else
414                                Gdk::Cairo::set_source_rgba(cr, white);
415    
416                            cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
417                            cr->fill();
418    
419                            // draw text showing the beginning of the dimension zone
420                            // as numeric value to the user
421                            {
422                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
423                                layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
424                                Gdk::Cairo::set_source_rgba(cr, black);
425                                // get the text dimensions
426                                int text_width, text_height;
427                                layout->get_pixel_size(text_width, text_height);
428                                // move text to the left end of the dimension zone
429                                cr->move_to(prevX + 3, y + (h - text_height) / 2);
430    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
431                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
432    #else
433                                layout->show_in_cairo_context(cr);
434    #endif
435                            }
436                            // draw text showing the end of the dimension zone
437                            // as numeric value to the user
438                            {
439                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
440                                layout->set_text(Glib::Ascii::dtostr(upperLimit));
441                                Gdk::Cairo::set_source_rgba(cr, black);
442                                // get the text dimensions
443                                int text_width, text_height;
444                                layout->get_pixel_size(text_width, text_height);
445                                // move text to the left end of the dimension zone
446                                cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
447    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
448                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
449    #else
450                                layout->show_in_cairo_context(cr);
451    #endif
452                          }                          }
453                          x1 = x2;  
454                            prevX = x;
455                            prevUpperLimit = upperLimit;
456                      }                      }
457                  } else {                  } else {
458                      if (dr < nbZones) {                      int prevX = 0;
459                          int x1 = int((w - label_width - 1) * dr / double(nbZones) + 0.5);                      for (int j = 0 ; j <= nbZones ; j++) {
460                          int x2 = int((w - label_width - 1) * (dr + 1) / double(nbZones) + 0.5);                          // draw dimension zone's borders for normal splits
461                          window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,                          int x = int((w - label_width - 1) * j /
462                                                 (x2 - x1) - 1, h - 2);                                      double(nbZones) + 0.5) + label_width;
463                      }                          if (x >= clipx2) break;
464                            if (x < clipx1) continue;
465                            Gdk::Cairo::set_source_rgba(cr, black);
466                            cr->move_to(x + 0.5, y + 1);
467                            cr->line_to(x + 0.5, y + h - 1);
468                            cr->stroke();
469    
470                            if (j != 0) {
471                                // draw fill for zone
472                                bool isSelectedZone = this->dimzones[dimension].count(j-1);
473                                bool isMainSelection =
474                                    this->maindimcase.find(dimension) != this->maindimcase.end() &&
475                                    this->maindimcase[dimension] == (j-1);
476                                if (isMainSelection)
477                                    Gdk::Cairo::set_source_rgba(cr, blue);
478                                else if (isSelectedZone)
479                                    cr->set_source(blueHatchedSurfacePattern);
480                                else
481                                    Gdk::Cairo::set_source_rgba(cr, white);
482                                cr->rectangle(prevX + 1, y + 1, x - prevX - 1, h - 1);
483                                cr->fill();
484    
485                                // draw text showing the beginning of the dimension zone
486                                // as numeric value to the user
487                                {
488                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
489                                    layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
490                                    Gdk::Cairo::set_source_rgba(cr, black);
491                                    // get the text dimensions
492                                    int text_width, text_height;
493                                    layout->get_pixel_size(text_width, text_height);
494                                    // move text to the left end of the dimension zone
495                                    cr->move_to(prevX + 3, y + (h - text_height) / 2);
496    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
497                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
498    #else
499                                    layout->show_in_cairo_context(cr);
500    #endif
501                                }
502                                // draw text showing the end of the dimension zone
503                                // as numeric value to the user
504                                {
505                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
506                                    layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
507                                    Gdk::Cairo::set_source_rgba(cr, black);
508                                    // get the text dimensions
509                                    int text_width, text_height;
510                                    layout->get_pixel_size(text_width, text_height);
511                                    // move text to the left end of the dimension zone
512                                    cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
513    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
514                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
515    #else
516                                    layout->show_in_cairo_context(cr);
517    #endif
518                                }
519                            }
520                            prevX = x;
521                        }      
522                  }                  }
523              }              }
   
524              y += h;              y += h;
525          }          }
526          bitpos += region->pDimensionDefinitions[i].bits;          bitpos += region->pDimensionDefinitions[i].bits;
# Line 228  bool DimRegionChooser::on_expose_event(G Line 529  bool DimRegionChooser::on_expose_event(G
529      return true;      return true;
530  }  }
531    
 void DimRegionChooser::on_size_request(GtkRequisition* requisition)  
 {  
     *requisition = GtkRequisition();  
     requisition->height = region ? nbDimensions * 20 : 0;  
     requisition->width = 800;  
 }  
   
532  void DimRegionChooser::set_region(gig::Region* region)  void DimRegionChooser::set_region(gig::Region* region)
533  {  {
534      this->region = region;      this->region = region;
535      dimregno = 0;      maindimregno = 0;
536      nbDimensions = 0;      nbDimensions = 0;
537      if (region) {      if (region) {
538          int bitcount = 0;          int bitcount = 0;
# Line 246  void DimRegionChooser::set_region(gig::R Line 540  void DimRegionChooser::set_region(gig::R
540              if (region->pDimensionDefinitions[dim].bits == 0) continue;              if (region->pDimensionDefinitions[dim].bits == 0) continue;
541              nbDimensions++;              nbDimensions++;
542    
543              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
544                               region->pDimensionDefinitions[dim].zones - 1);                               region->pDimensionDefinitions[dim].zones - 1);
545              dimregno |= (z << bitcount);              maindimregno |= (z << bitcount);
546              bitcount += region->pDimensionDefinitions[dim].bits;              bitcount += region->pDimensionDefinitions[dim].bits;
547          }          }
         dimreg = region->pDimensionRegions[dimregno];  
     } else {  
         dimreg = 0;  
548      }      }
549      dimregion_selected();      dimregion_selected();
550        set_size_request(800, region ? nbDimensions * h : 0);
551    
552        labels_changed = true;
553      queue_resize();      queue_resize();
554        queue_draw();
555  }  }
556    
557    void DimRegionChooser::refresh_all() {
558        set_region(region);
559    }
560    
561  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
562                                        std::set<gig::DimensionRegion*>& dimregs) const                                        std::set<gig::DimensionRegion*>& dimregs) const
563  {  {
564      int dimregno = 0;      for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
565      int bitcount = 0;          gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
566      int stereo_bit = 0;          if (!dimRgn) continue;
567      for (int dim = 0 ; dim < region->Dimensions ; dim++) {          bool isValidZone;
568          if (region->pDimensionDefinitions[dim].bits == 0) continue;          std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
569          if (stereo &&          if (!isValidZone) continue;
570              region->pDimensionDefinitions[dim].dimension == gig::dimension_samplechannel) {          for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
571              stereo_bit = (1 << bitcount);               it != dimCase.end(); ++it)
572          } else {          {
573              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
574                               region->pDimensionDefinitions[dim].zones - 1);  
575              dimregno |= (z << bitcount);              std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
576                    this->dimzones.find(it->first);
577                if (itSelectedDimension != this->dimzones.end() &&
578                    itSelectedDimension->second.count(it->second)) continue; // is selected
579    
580                goto notSelected;
581          }          }
582          bitcount += region->pDimensionDefinitions[dim].bits;  
583            dimregs.insert(dimRgn);
584    
585            notSelected:
586            ;
587      }      }
     dimregs.insert(region->pDimensionRegions[dimregno]);  
     if (stereo_bit) dimregs.insert(region->pDimensionRegions[dimregno | stereo_bit]);  
588  }  }
589    
590    void DimRegionChooser::update_after_resize()
 bool DimRegionChooser::on_button_release_event(GdkEventButton* event)  
591  {  {
592      if (resize.active) {      const uint8_t upperLimit = resize.pos - 1;
593          get_window()->pointer_ungrab(event->time);      gig::Instrument* instr = (gig::Instrument*)region->GetParent();
594          resize.active = false;  
595        int bitpos = 0;
596        for (int j = 0 ; j < resize.dimension ; j++) {
597            bitpos += region->pDimensionDefinitions[j].bits;
598        }
599    
600          if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {      const int stereobitpos =
601            (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
602    
603              int bitpos = 0;      // the velocity dimension must be handled differently than all other
604              for (int j = 0 ; j < resize.dimension ; j++) {      // dimension types, because
605                  bitpos += region->pDimensionDefinitions[j].bits;      // 1. it is currently the only dimension type which allows different zone
606        //    sizes for different cases
607        // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
608        if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
609            int mask =
610                ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
611            int c = maindimregno & mask; // mask away this dimension
612    
613            if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
614                // the velocity dimension didn't previously have
615                // custom v3 splits, so we initialize all splits with
616                // default values
617                int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
618                for (int j = 0 ; j < nbZones ; j++) {
619                    gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
620                    d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
621              }              }
622              int mask =          }
623                  ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);          if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {
624              int c = dimregno & mask; // mask away this dimension              // the velocity dimension didn't previously have
625                // custom v2 splits, so we initialize all splits with
626              if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {              // default values
627                  // the velocity dimension didn't previously have              int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
628                  // custom v3 splits, so we initialize all splits with              for (int j = 0 ; j < nbZones ; j++) {
629                  // default values                  gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
630                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);
631                  for (int j = 0 ; j < nbZones ; j++) {              }
632                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];          }
633                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);  
634            int index = c + (resize.zone << bitpos);
635            gig::DimensionRegion* d = region->pDimensionRegions[index];
636            // update both v2 and v3 values
637            d->DimensionUpperLimits[resize.dimension] = upperLimit;
638            d->VelocityUpperLimit = upperLimit;
639            if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
640                gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
641                d->DimensionUpperLimits[resize.dimension] = upperLimit;
642                d->VelocityUpperLimit = upperLimit;
643            }
644    
645            if (modifyalldimregs) {
646                gig::Region* rgn = NULL;
647                for (int key = 0; key < 128; ++key) {
648                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
649                    rgn = instr->GetRegion(key);
650                    if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
651                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
652                    if (!dimdef) continue;
653                    if (dimdef->zones != resize.dimensionDef.zones) continue;
654                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
655                    assert(iDim >= 0 && iDim < rgn->Dimensions);
656    
657                    // the dimension layout might be completely different in this
658                    // region, so we have to recalculate bitpos etc for this region
659                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
660                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
661                    const int selection = resize.zone << bitpos;
662    
663                    // primitive and inefficient loop implementation, however due to
664                    // this circumstance the loop code is much simpler, and its lack
665                    // of runtime efficiency should not be notable in practice
666                    for (int idr = 0; idr < 256; ++idr) {
667                        const int index = (idr & stencil) | selection;
668                        assert(index >= 0 && index < 256);
669                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
670                        if (!dr) continue;
671                        dr->DimensionUpperLimits[iDim] = upperLimit;
672                        d->VelocityUpperLimit = upperLimit;
673                  }                  }
674              }              }
675              if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {          } else if (modifyallregions) { // implies modifyalldimregs is false ...
676                  // the velocity dimension didn't previously have              // resolve the precise case we need to modify for all other regions
677                  // custom v2 splits, so we initialize all splits with              DimensionCase dimCase = dimensionCaseOf(d);
678                  // default values              // apply the velocity upper limit change to that resolved dim case
679                // of all regions ...
680                gig::Region* rgn = NULL;
681                for (int key = 0; key < 128; ++key) {
682                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
683                    rgn = instr->GetRegion(key);
684                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
685                    if (!dimdef) continue;
686                    if (dimdef->zones != resize.dimensionDef.zones) continue;
687                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
688                    assert(iDim >= 0 && iDim < rgn->Dimensions);
689    
690                    std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
691                    for (int i = 0; i < dimrgns.size(); ++i) {
692                        gig::DimensionRegion* dr = dimrgns[i];
693                        dr->DimensionUpperLimits[iDim] = upperLimit;
694                        dr->VelocityUpperLimit = upperLimit;
695                    }
696                }
697            }
698        } else {
699            for (int i = 0 ; i < region->DimensionRegions ; ) {
700                if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
701                    // the dimension didn't previously have custom
702                    // limits, so we have to set default limits for
703                    // all the dimension regions
704                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
705    
706                  for (int j = 0 ; j < nbZones ; j++) {                  for (int j = 0 ; j < nbZones ; j++) {
707                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];                      gig::DimensionRegion* d = region->pDimensionRegions[i + (j << bitpos)];
708                      d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
709                  }                  }
710              }              }
711                int index = i + (resize.zone << bitpos);
712              gig::DimensionRegion *d = region->pDimensionRegions[c + resize.offset];              gig::DimensionRegion* d = region->pDimensionRegions[index];
713              // update both v2 and v3 values              d->DimensionUpperLimits[resize.dimension] = upperLimit;
714              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
715              d->VelocityUpperLimit = resize.pos - 1;              if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
716                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
717          } else {                  d->DimensionUpperLimits[resize.dimension] = upperLimit;
718              for (int i = 0 ; i < region->DimensionRegions ; ) {              }
719    #endif
720                  if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              int bitpos = 0;
721                      // the dimension didn't previously have custom              int j;
722                      // limits, so we have to set default limits for              for (j = 0 ; j < region->Dimensions ; j++) {
723                      // all the dimension regions                  if (j != resize.dimension) {
724                      int bitpos = 0;                      int maxzones = 1 << region->pDimensionDefinitions[j].bits;
725                      for (int j = 0 ; j < resize.dimension ; j++) {                      int dimj = (i >> bitpos) & (maxzones - 1);
726                          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);  
                     }  
727                  }                  }
728                  gig::DimensionRegion *d = region->pDimensionRegions[i + resize.offset];                  bitpos += region->pDimensionDefinitions[j].bits;
729                  d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              }
730                if (j == region->Dimensions) break;
731                i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
732            }
733    
734                  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
735                  int j;              gig::Region* rgn = NULL;
736                  for (j = 0 ; j < region->Dimensions ; j++) {              for (int key = 0; key < 128; ++key) {
737                      if (j != resize.dimension) {                  if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
738                          int maxzones = 1 << region->pDimensionDefinitions[j].bits;                  rgn = instr->GetRegion(key);
739                          int dimj = (i >> bitpos) & (maxzones - 1);                  gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
740                          if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;                  if (!dimdef) continue;
741                      }                  if (dimdef->zones != resize.dimensionDef.zones) continue;
742                      bitpos += region->pDimensionDefinitions[j].bits;                  const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
743                    assert(iDim >= 0 && iDim < rgn->Dimensions);
744    
745                    // the dimension layout might be completely different in this
746                    // region, so we have to recalculate bitpos etc for this region
747                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
748                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
749                    const int selection = resize.zone << bitpos;
750    
751                    // this loop implementation is less efficient than the above's
752                    // loop implementation (which skips unnecessary dimension regions)
753                    // however this code is much simpler, and its lack of runtime
754                    // efficiency should not be notable in practice
755                    for (int idr = 0; idr < 256; ++idr) {
756                        const int index = (idr & stencil) | selection;
757                        assert(index >= 0 && index < 256);
758                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
759                        if (!dr) continue;
760                        dr->DimensionUpperLimits[iDim] = upperLimit;
761                  }                  }
                 if (j == region->Dimensions) break;  
                 i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);  
762              }              }
763          }          }
764        }
765    }
766    
767    bool DimRegionChooser::on_button_release_event(GdkEventButton* event)
768    {
769        if (resize.active) {
770    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
771            get_window()->pointer_ungrab(event->time);
772    #else
773            Glib::wrap(event->device, true)->ungrab(event->time);
774    #endif
775            resize.active = false;
776    
777          region_changed();          region_changed();
778    
779          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 377  bool DimRegionChooser::on_button_press_e Line 791  bool DimRegionChooser::on_button_press_e
791          event->x >= label_width && event->x < w) {          event->x >= label_width && event->x < w) {
792    
793          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
794              Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
795              get_window()->pointer_grab(false,              get_window()->pointer_grab(false,
796                                         Gdk::BUTTON_RELEASE_MASK |                                         Gdk::BUTTON_RELEASE_MASK |
797                                         Gdk::POINTER_MOTION_MASK |                                         Gdk::POINTER_MOTION_MASK |
798                                         Gdk::POINTER_MOTION_HINT_MASK,                                         Gdk::POINTER_MOTION_HINT_MASK,
799                                         double_arrow, event->time);                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
800                                           event->time);
801    #else
802                Glib::wrap(event->device, true)->grab(get_window(),
803                                                      Gdk::OWNERSHIP_NONE,
804                                                      false,
805                                                      Gdk::BUTTON_RELEASE_MASK |
806                                                      Gdk::POINTER_MOTION_MASK |
807                                                      Gdk::POINTER_MOTION_HINT_MASK,
808                                                      Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
809                                                      event->time);
810    #endif
811              resize.active = true;              resize.active = true;
812          } else {          } else {
813              int ydim = int(event->y / h);              int ydim = int(event->y / h);
# Line 401  bool DimRegionChooser::on_button_press_e Line 826  bool DimRegionChooser::on_button_press_e
826              }              }
827    
828              int i = dim;              int i = dim;
829              if (dimregno < 0) dimregno = 0;              if (maindimregno < 0) maindimregno = 0;
830              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
831              int c = dimregno & mask; // mask away this dimension              int c = this->maindimregno & mask; // mask away this dimension
832    
833              bool customsplits =              bool customsplits =
834                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&                  ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
# Line 415  bool DimRegionChooser::on_button_press_e Line 840  bool DimRegionChooser::on_button_press_e
840    
841                  if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {                  if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {
842                      for (z = 0 ; z < nbZones ; z++) {                      for (z = 0 ; z < nbZones ; z++) {
843                          gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];                          gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
844                          if (val <= d->DimensionUpperLimits[i]) break;                          if (val <= d->DimensionUpperLimits[i]) break;
845                      }                      }
846                  } else {                  } else {
847                      for (z = 0 ; z < nbZones ; z++) {                      for (z = 0 ; z < nbZones ; z++) {
848                          gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];                          gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
849                          if (val <= d->VelocityUpperLimit) break;                          if (val <= d->VelocityUpperLimit) break;
850                      }                      }
851                  }                  }
# Line 433  bool DimRegionChooser::on_button_press_e Line 858  bool DimRegionChooser::on_button_press_e
858                     region->pDimensionDefinitions[dim].split_type,                     region->pDimensionDefinitions[dim].split_type,
859                     region->pDimensionDefinitions[dim].zones,                     region->pDimensionDefinitions[dim].zones,
860                     region->pDimensionDefinitions[dim].zone_size);                     region->pDimensionDefinitions[dim].zone_size);
861              dimvalue[region->pDimensionDefinitions[dim].dimension] = z;              this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
862                this->maindimregno = c | (z << bitpos);
863              dimregno = c | (z << bitpos);              this->maindimtype = region->pDimensionDefinitions[dim].dimension;
864    
865                if (multiSelectKeyDown) {
866                    if (dimzones[this->maindimtype].count(z)) {
867                        if (dimzones[this->maindimtype].size() > 1) {
868                            dimzones[this->maindimtype].erase(z);
869                        }
870                    } else {
871                        dimzones[this->maindimtype].insert(z);
872                    }
873                } else {
874                    this->dimzones.clear();
875                    for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
876                         it != this->maindimcase.end(); ++it)
877                    {
878                        this->dimzones[it->first].insert(it->second);
879                    }
880                }
881    
882              focus_line = dim;              focus_line = dim;
883              if (has_focus()) queue_draw();              if (has_focus()) queue_draw();
884              else grab_focus();              else grab_focus();
             dimreg = region->pDimensionRegions[dimregno];  
885              dimregion_selected();              dimregion_selected();
886    
887                if (event->button == 3) {
888                    printf("dimregion right click\n");
889                    popup_menu_inside_dimregion->popup(event->button, event->time);
890                }
891    
892                queue_draw();
893          }          }
894      }      }
895      return true;      return true;
# Line 464  bool DimRegionChooser::on_motion_notify_ Line 912  bool DimRegionChooser::on_motion_notify_
912          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
913    
914          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();  
   
915              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;
916              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;
917              int y = resize.dimension * h;              int y = resize.dimension * h;
918                int x1, x2;
919              if (resize.selected == resize.none) {              if (k > resize.pos) {
920                  if (resize.pos != resize.min && resize.pos != resize.max) {                  x1 = prevx;
921                      window->draw_line(white, prevx, y + 1, prevx, y + h - 2);                  x2 = x;
                 }  
922              } else {              } else {
923                  gc->set_foreground(red);                  x1 = x;
924                    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);  
                 }  
925              }              }
926              window->draw_line(black, x, y + 1, x, y + h - 2);              Gdk::Rectangle rect(x1, y + 1, x2 - x1 + 1, h - 2);
927    
928              resize.pos = k;              resize.pos = k;
929                update_after_resize();
930                get_window()->invalidate_rect(rect, false); // not sufficient ...
931                queue_draw(); // ... so do a complete redraw instead.
932          }          }
933      } else {      } else {
934          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
935              if (!cursor_is_resize) {              if (!cursor_is_resize) {
936                  Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
937                  window->set_cursor(double_arrow);                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
938    #else
939                    window->set_cursor(Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW));
940    #endif
941                  cursor_is_resize = true;                  cursor_is_resize = true;
942              }              }
943          } else if (cursor_is_resize) {          } else if (cursor_is_resize) {
# Line 532  bool DimRegionChooser::is_in_resize_zone Line 964  bool DimRegionChooser::is_in_resize_zone
964          int nbZones = region->pDimensionDefinitions[dim].zones;          int nbZones = region->pDimensionDefinitions[dim].zones;
965    
966          int c = 0;          int c = 0;
967          if (dimregno >= 0) {          if (maindimregno >= 0) {
968              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
969              c = dimregno & mask; // mask away this dimension              c = maindimregno & mask; // mask away this dimension
970          }          }
971          const bool customsplits =          const bool customsplits =
972              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&              ((region->pDimensionDefinitions[dim].split_type == gig::split_type_normal &&
# Line 546  bool DimRegionChooser::is_in_resize_zone Line 978  bool DimRegionChooser::is_in_resize_zone
978          if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {          if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {
979              int prev_limit = 0;              int prev_limit = 0;
980              for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {              for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {
981                  gig::DimensionRegion *d = region->pDimensionRegions[c + (iZone << bitpos)];                  gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
982                  const int upperLimit =                  const int upperLimit =
983                      (customsplits) ?                      (customsplits) ?
984                          (d->DimensionUpperLimits[dim]) ?                          (d->DimensionUpperLimits[dim]) ?
# Line 557  bool DimRegionChooser::is_in_resize_zone Line 989  bool DimRegionChooser::is_in_resize_zone
989                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
990                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
991                      resize.dimension = dim;                      resize.dimension = dim;
992                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
993                        resize.zone = iZone;
994                      resize.pos = limit;                      resize.pos = limit;
995                      resize.min = prev_limit;                      resize.min = prev_limit;
996    
997                      int dr = (dimregno >> bitpos) &                      int dr = (maindimregno >> bitpos) &
998                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);
999                      resize.selected = dr == iZone ? resize.left :                      resize.selected = dr == iZone ? resize.left :
1000                          dr == iZone + 1 ? resize.right : resize.none;                          dr == iZone + 1 ? resize.right : resize.none;
1001    
1002                      iZone++;                      iZone++;
1003                      gig::DimensionRegion *d = region->pDimensionRegions[c + (iZone << bitpos)];                      gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
1004    
1005                      const int upperLimit =                      const int upperLimit =
1006                          (customsplits) ?                          (customsplits) ?
# Line 598  sigc::signal<void>& DimRegionChooser::si Line 1031  sigc::signal<void>& DimRegionChooser::si
1031    
1032  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
1033  {  {
1034      // TODO: kolla att region finns osv, dvs att det går att sätta      // TODO: check that region exists etc, that is, that it's possible
1035      // fokus.      // to set focus
1036      if (direction == Gtk::DIR_TAB_FORWARD ||      if (direction == Gtk::DIR_TAB_FORWARD ||
1037          direction == Gtk::DIR_DOWN) {          direction == Gtk::DIR_DOWN) {
1038          if (!has_focus()) {          if (!has_focus()) {
# Line 631  bool DimRegionChooser::on_focus(Gtk::Dir Line 1064  bool DimRegionChooser::on_focus(Gtk::Dir
1064              }              }
1065          }          }
1066      } else if (!has_focus()) {      } else if (!has_focus()) {
1067          // TODO: kolla att focus_line finns!          // TODO: check that focus_line exists
1068          grab_focus();          grab_focus();
1069          return true;          return true;
1070      } else {      } else {
1071          // TODO: öka eller minska värde!          // TODO: increase or decrease value
1072        }
1073        return false;
1074    }
1075    
1076    void DimRegionChooser::split_dimension_zone() {    
1077        printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1078        try {
1079            if (!modifyallregions) {
1080                region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1081            } else {
1082                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1083                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1084                assert(pMaindimdef != NULL);
1085                // retain structure by value since the original region will be
1086                // modified in the loop below as well
1087                gig::dimension_def_t maindimdef = *pMaindimdef;
1088                std::vector<gig::Region*> ignoredAll;
1089                std::vector<gig::Region*> ignoredMinor;
1090                std::vector<gig::Region*> ignoredCritical;
1091                gig::Region* rgn = NULL;
1092                for (int key = 0; key < 128; ++key) {
1093                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1094                    rgn = instr->GetRegion(key);
1095    
1096                    // ignore all regions which do not exactly match the dimension
1097                    // layout of the selected region where this operation was emitted
1098                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1099                    if (!dimdef) {
1100                        ignoredAll.push_back(rgn);
1101                        ignoredMinor.push_back(rgn);
1102                        continue;
1103                    }
1104                    if (dimdef->zones != maindimdef.zones) {
1105                        ignoredAll.push_back(rgn);
1106                        ignoredCritical.push_back(rgn);
1107                        continue;
1108                    }
1109    
1110                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1111                }
1112                if (!ignoredAll.empty()) {
1113                    Glib::ustring txt;
1114                    if (ignoredCritical.empty())
1115                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1116                    else if (ignoredMinor.empty())
1117                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1118                    else
1119                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1120                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1121                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1122                    Gtk::MessageDialog msg(txt, false, type);
1123                    msg.run();
1124                }
1125            }
1126        } catch (RIFF::Exception e) {
1127            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1128            msg.run();
1129        } catch (...) {
1130            Glib::ustring txt = _("An unknown exception occurred!");
1131            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1132            msg.run();
1133        }
1134        refresh_all();
1135    }
1136    
1137    void DimRegionChooser::delete_dimension_zone() {
1138        printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1139        try {
1140            if (!modifyallregions) {
1141                region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1142            } else {
1143                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1144                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1145                assert(pMaindimdef != NULL);
1146                // retain structure by value since the original region will be
1147                // modified in the loop below as well
1148                gig::dimension_def_t maindimdef = *pMaindimdef;
1149                std::vector<gig::Region*> ignoredAll;
1150                std::vector<gig::Region*> ignoredMinor;
1151                std::vector<gig::Region*> ignoredCritical;
1152                gig::Region* rgn = NULL;
1153                for (int key = 0; key < 128; ++key) {
1154                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1155                    rgn = instr->GetRegion(key);
1156    
1157                    // ignore all regions which do not exactly match the dimension
1158                    // layout of the selected region where this operation was emitted
1159                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1160                    if (!dimdef) {
1161                        ignoredAll.push_back(rgn);
1162                        ignoredMinor.push_back(rgn);
1163                        continue;
1164                    }
1165                    if (dimdef->zones != maindimdef.zones) {
1166                        ignoredAll.push_back(rgn);
1167                        ignoredCritical.push_back(rgn);
1168                        continue;
1169                    }
1170    
1171                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1172                }
1173                if (!ignoredAll.empty()) {
1174                    Glib::ustring txt;
1175                    if (ignoredCritical.empty())
1176                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1177                    else if (ignoredMinor.empty())
1178                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1179                    else
1180                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1181                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1182                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1183                    Gtk::MessageDialog msg(txt, false, type);
1184                    msg.run();
1185                }
1186            }
1187        } catch (RIFF::Exception e) {
1188            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1189            msg.run();
1190        } catch (...) {
1191            Glib::ustring txt = _("An unknown exception occurred!");
1192            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1193            msg.run();
1194      }      }
1195        refresh_all();
1196    }
1197    
1198    // Cmd key on Mac, Ctrl key on all other OSs
1199    static const guint primaryKeyL =
1200        #if defined(__APPLE__)
1201        GDK_KEY_Meta_L;
1202        #else
1203        GDK_KEY_Control_L;
1204        #endif
1205    
1206    static const guint primaryKeyR =
1207        #if defined(__APPLE__)
1208        GDK_KEY_Meta_R;
1209        #else
1210        GDK_KEY_Control_R;
1211        #endif
1212    
1213    bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1214        //printf("key down 0x%x\n", key->keyval);
1215        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1216            multiSelectKeyDown = true;
1217        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1218            primaryKeyDown = true;
1219        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1220            shiftKeyDown = true;
1221    
1222        //FIXME: hmm, for some reason GDKMM does not fire arrow key down events, so we are doing those handlers in the key up handler instead for now
1223        /*if (key->keyval == GDK_KEY_Left)
1224            select_prev_dimzone();
1225        if (key->keyval == GDK_KEY_Right)
1226            select_next_dimzone();
1227        if (key->keyval == GDK_KEY_Up)
1228            select_prev_dimension();
1229        if (key->keyval == GDK_KEY_Down)
1230            select_next_dimension();*/
1231        return false;
1232    }
1233    
1234    bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1235        //printf("key up 0x%x\n", key->keyval);
1236        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1237            multiSelectKeyDown = false;
1238        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1239            primaryKeyDown = false;
1240        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1241            shiftKeyDown = false;
1242    
1243        if (!has_focus()) return false;
1244    
1245        // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow
1246        // (which is supposed to switch between regions)
1247        if (primaryKeyDown) return false;
1248    
1249        if (key->keyval == GDK_KEY_Left)
1250            select_prev_dimzone();
1251        if (key->keyval == GDK_KEY_Right)
1252            select_next_dimzone();
1253        if (key->keyval == GDK_KEY_Up)
1254            select_prev_dimension();
1255        if (key->keyval == GDK_KEY_Down)
1256            select_next_dimension();
1257    
1258        return false;
1259    }
1260    
1261    void DimRegionChooser::resetSelectedZones() {
1262        this->dimzones.clear();
1263        if (!region) {
1264            queue_draw(); // redraw required parts
1265            return;
1266        }
1267        if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1268            queue_draw(); // redraw required parts
1269            return;
1270        }
1271        if (!region->pDimensionRegions[maindimregno]) {
1272            queue_draw(); // redraw required parts
1273            return;
1274        }
1275        gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1276    
1277        bool isValidZone;
1278        this->maindimcase = dimensionCaseOf(dimrgn);
1279    
1280        for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1281             it != this->maindimcase.end(); ++it)
1282        {
1283            this->dimzones[it->first].insert(it->second);
1284        }
1285    
1286        // redraw required parts
1287        queue_draw();
1288    }
1289    
1290    bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1291        if (!region) return false; //.selection failed
1292    
1293        for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1294            if (region->pDimensionRegions[dr] == dimrgn) {
1295                // reset dim region zone selection to the requested specific dim region case
1296                maindimregno = dr;
1297                resetSelectedZones();
1298    
1299                // emit signal that dimregion selection has changed, for external entities
1300                dimregion_selected();
1301    
1302                return true; // selection success
1303            }
1304        }
1305    
1306        return false; //.selection failed
1307    }
1308    
1309    void DimRegionChooser::select_next_dimzone() {
1310        select_dimzone_by_dir(+1);
1311    }
1312    
1313    void DimRegionChooser::select_prev_dimzone() {
1314        select_dimzone_by_dir(-1);
1315    }
1316    
1317    void DimRegionChooser::select_dimzone_by_dir(int dir) {
1318        if (!region) return;
1319        if (!region->Dimensions) return;
1320        if (focus_line < 0) focus_line = 0;
1321        if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1322    
1323        maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1324        if (maindimtype == gig::dimension_none) {
1325            printf("maindimtype -> none\n");
1326            return;
1327        }
1328    
1329        if (maindimcase.empty()) {
1330            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1331            if (maindimcase.empty()) {
1332                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1333                return;
1334            }
1335        }
1336    
1337        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1338        if (z < 0) z = 0;
1339        if (z >= region->pDimensionDefinitions[focus_line].zones)
1340            z = region->pDimensionDefinitions[focus_line].zones - 1;
1341    
1342        maindimcase[maindimtype] = z;
1343    
1344        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1345        if (!dr) {
1346            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1347            return;
1348        }
1349    
1350        maindimregno = getDimensionRegionIndex(dr);
1351    
1352        // reset selected dimregion zones
1353        dimzones.clear();
1354        for (DimensionCase::const_iterator it = maindimcase.begin();
1355             it != maindimcase.end(); ++it)
1356        {
1357            dimzones[it->first].insert(it->second);
1358        }
1359    
1360        dimregion_selected();
1361    
1362        // disabled: would overwrite dimregno with wrong value
1363        //refresh_all();
1364        // so requesting just a raw repaint instead:
1365        queue_draw();
1366    }
1367    
1368    void DimRegionChooser::select_next_dimension() {
1369        if (!region) return;
1370        focus_line++;
1371        if (focus_line >= region->Dimensions)
1372            focus_line = region->Dimensions - 1;
1373        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1374        queue_draw();
1375    }
1376    
1377    void DimRegionChooser::select_prev_dimension() {
1378        if (!region) return;
1379        focus_line--;
1380        if (focus_line < 0)
1381            focus_line = 0;
1382        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1383        queue_draw();
1384    }
1385    
1386    gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1387        if (!region) return NULL;
1388        return region->pDimensionRegions[maindimregno];
1389  }  }

Legend:
Removed from v.1623  
changed lines
  Added in v.3132

  ViewVC Help
Powered by ViewVC