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

Legend:
Removed from v.1656  
changed lines
  Added in v.3147

  ViewVC Help
Powered by ViewVC