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

Legend:
Removed from v.2151  
changed lines
  Added in v.3158

  ViewVC Help
Powered by ViewVC