/[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 3364 by schoenebeck, Tue Nov 14 18:07:25 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 "global.h"
21    #include "compat.h"
22    #include <gtkmm/box.h>
23  #include "dimregionchooser.h"  #include "dimregionchooser.h"
24    #include <cairomm/context.h>
25    #include <cairomm/surface.h>
26  #include <gdkmm/cursor.h>  #include <gdkmm/cursor.h>
27    #include <gdkmm/general.h>
28    #if HAS_GDKMM_SEAT
29    # include <gdkmm/seat.h>
30    #endif
31    #include <glibmm/stringutils.h>
32    #if HAS_GTKMM_STOCK
33    # include <gtkmm/stock.h>
34    #endif
35    #include <glibmm/ustring.h>
36    #include <gtkmm/messagedialog.h>
37    #include <assert.h>
38    
39    #include "gfx/builtinpix.h"
40    
41    //TODO: this function and dimensionCaseOf() from global.h are duplicates, eliminate either one of them!
42    static DimensionCase caseOfDimRegion(gig::DimensionRegion* dr, bool* isValidZone) {
43        DimensionCase dimCase;
44        if (!dr) {
45            *isValidZone = false;
46            return dimCase;
47        }
48    
49        gig::Region* rgn = (gig::Region*) dr->GetParent();
50    
51        // find the dimension region index of the passed dimension region
52        int drIndex;
53        for (drIndex = 0; drIndex < 256; ++drIndex)
54            if (rgn->pDimensionRegions[drIndex] == dr)
55                break;
56    
57        // not found in region, something's horribly wrong
58        if (drIndex == 256) {
59            fprintf(stderr, "DimRegionChooser: ERROR: index of dim region not found!\n");
60            *isValidZone = false;
61            return DimensionCase();
62        }
63    
64        for (int d = 0, baseBits = 0; d < rgn->Dimensions; ++d) {
65            const int bits = rgn->pDimensionDefinitions[d].bits;
66            dimCase[rgn->pDimensionDefinitions[d].dimension] =
67                (drIndex >> baseBits) & ((1 << bits) - 1);
68            baseBits += bits;
69            // there are also DimensionRegion objects of unused zones, skip them
70            if (dimCase[rgn->pDimensionDefinitions[d].dimension] >= rgn->pDimensionDefinitions[d].zones) {
71                *isValidZone = false;
72                return DimensionCase();
73            }
74        }
75    
76  DimRegionChooser::DimRegionChooser()      *isValidZone = true;
77        return dimCase;
78    }
79    
80    DimRegionChooser::DimRegionChooser(Gtk::Window& window) :
81        red("#ff476e"),
82        blue("#4796ff"),
83        black("black"),
84        white("white")
85  {  {
86      // get_window() would return 0 because the Gdk::Window has not yet been realized      // make sure blue hatched pattern pixmap is loaded
87      // So we can only allocate the colors here - the rest will happen in on_realize().      loadBuiltInPix();
88      Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();  
89        // create blue hatched pattern 1
90      black = Gdk::Color("black");      {
91      white = Gdk::Color("white");          const int width = blueHatchedPattern->get_width();
92      red = Gdk::Color("#8070ff");          const int height = blueHatchedPattern->get_height();
93      blue = Gdk::Color("blue");          const int stride = blueHatchedPattern->get_rowstride();
94      green = Gdk::Color("green");  
95            // manually convert from RGBA to ARGB
96      colormap->alloc_color(black);          this->blueHatchedPatternARGB = blueHatchedPattern->copy();
97      colormap->alloc_color(white);          const int pixelSize = stride / width;
98      colormap->alloc_color(red);          const int totalPixels = width * height;
99      colormap->alloc_color(blue);          assert(pixelSize == 4);
100      colormap->alloc_color(green);          unsigned char* ptr = this->blueHatchedPatternARGB->get_pixels();
101            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
102                const unsigned char r = ptr[0];
103                const unsigned char g = ptr[1];
104                const unsigned char b = ptr[2];
105                const unsigned char a = ptr[3];
106                ptr[0] = b;
107                ptr[1] = g;
108                ptr[2] = r;
109                ptr[3] = a;
110            }
111    
112            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
113    #if HAS_CAIROMM_CPP11_ENUMS
114                this->blueHatchedPatternARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
115    #else
116                this->blueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
117    #endif
118            );
119            this->blueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
120    #if HAS_CAIROMM_CPP11_ENUMS
121            this->blueHatchedSurfacePattern->set_extend(Cairo::Pattern::Extend::REPEAT);
122    #else
123            this->blueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
124    #endif
125        }
126    
127        // create blue hatched pattern 2
128        {
129            const int width = blueHatchedPattern2->get_width();
130            const int height = blueHatchedPattern2->get_height();
131            const int stride = blueHatchedPattern2->get_rowstride();
132    
133            // manually convert from RGBA to ARGB
134            this->blueHatchedPattern2ARGB = blueHatchedPattern2->copy();
135            const int pixelSize = stride / width;
136            const int totalPixels = width * height;
137            assert(pixelSize == 4);
138            unsigned char* ptr = this->blueHatchedPattern2ARGB->get_pixels();
139            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
140                const unsigned char r = ptr[0];
141                const unsigned char g = ptr[1];
142                const unsigned char b = ptr[2];
143                const unsigned char a = ptr[3];
144                ptr[0] = b;
145                ptr[1] = g;
146                ptr[2] = r;
147                ptr[3] = a;
148            }
149    
150            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
151    #if HAS_CAIROMM_CPP11_ENUMS
152                this->blueHatchedPattern2ARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
153    #else
154                this->blueHatchedPattern2ARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
155    #endif
156            );
157            this->blueHatchedSurfacePattern2 = Cairo::SurfacePattern::create(imageSurface);
158    #if HAS_CAIROMM_CPP11_ENUMS
159            this->blueHatchedSurfacePattern2->set_extend(Cairo::Pattern::Extend::REPEAT);
160    #else
161            this->blueHatchedSurfacePattern2->set_extend(Cairo::EXTEND_REPEAT);
162    #endif
163        }
164    
165        // create gray blue hatched pattern
166        {
167            const int width = grayBlueHatchedPattern->get_width();
168            const int height = grayBlueHatchedPattern->get_height();
169            const int stride = grayBlueHatchedPattern->get_rowstride();
170    
171            // manually convert from RGBA to ARGB
172            this->grayBlueHatchedPatternARGB = grayBlueHatchedPattern->copy();
173            const int pixelSize = stride / width;
174            const int totalPixels = width * height;
175            assert(pixelSize == 4);
176            unsigned char* ptr = this->grayBlueHatchedPatternARGB->get_pixels();
177            for (int iPixel = 0; iPixel < totalPixels; ++iPixel, ptr += pixelSize) {
178                const unsigned char r = ptr[0];
179                const unsigned char g = ptr[1];
180                const unsigned char b = ptr[2];
181                const unsigned char a = ptr[3];
182                ptr[0] = b;
183                ptr[1] = g;
184                ptr[2] = r;
185                ptr[3] = a;
186            }
187    
188            Cairo::RefPtr<Cairo::ImageSurface> imageSurface = Cairo::ImageSurface::create(
189    #if HAS_CAIROMM_CPP11_ENUMS
190                this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::Surface::Format::ARGB32, width, height, stride
191    #else
192                this->grayBlueHatchedPatternARGB->get_pixels(), Cairo::FORMAT_ARGB32, width, height, stride
193    #endif
194            );
195            this->grayBlueHatchedSurfacePattern = Cairo::SurfacePattern::create(imageSurface);
196    #if HAS_CAIROMM_CPP11_ENUMS
197            this->grayBlueHatchedSurfacePattern->set_extend(Cairo::Pattern::Extend::REPEAT);
198    #else
199            this->grayBlueHatchedSurfacePattern->set_extend(Cairo::EXTEND_REPEAT);
200    #endif
201        }
202    
203      instrument = 0;      instrument = 0;
204      region = 0;      region = 0;
205      dimregno = -1;      maindimregno = -1;
206        maindimtype = gig::dimension_none; // initialize with invalid dimension type
207      focus_line = 0;      focus_line = 0;
208      resize.active = false;      resize.active = false;
209      cursor_is_resize = false;      cursor_is_resize = false;
210      h = 20;      h = 24;
211      set_flags(Gtk::CAN_FOCUS);      multiSelectKeyDown = false;
212        primaryKeyDown = false;
213        shiftKeyDown = false;
214        modifybothchannels = modifyalldimregs = modifybothchannels = false;
215        set_can_focus();
216    
217        const Glib::ustring txtUseCheckBoxAllRegions =
218            _("Use checkbox 'all regions' to control whether this should apply to all regions.");
219    
220        actionGroup = ActionGroup::create();
221    #if USE_GLIB_ACTION
222        actionSplitDimZone = actionGroup->add_action(
223            "SplitDimZone", sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
224        );
225        actionDeleteDimZone = actionGroup->add_action(
226             "DeleteDimZone", sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
227         );
228        insert_action_group("PopupMenuInsideDimRegion", actionGroup);
229    #else
230        actionSplitDimZone = Action::create("SplitDimZone", _("Split Dimensions Zone"), txtUseCheckBoxAllRegions);
231        actionSplitDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
232        actionGroup->add(
233            actionSplitDimZone,
234            sigc::mem_fun(*this, &DimRegionChooser::split_dimension_zone)
235        );
236        actionDeleteDimZone = Gtk::Action::create("DeleteDimZone", _("Delete Dimension Zone"), txtUseCheckBoxAllRegions);
237        actionDeleteDimZone->set_tooltip(txtUseCheckBoxAllRegions); //FIXME: doesn't work? why???
238        actionGroup->add(
239            actionDeleteDimZone,
240            sigc::mem_fun(*this, &DimRegionChooser::delete_dimension_zone)
241        );
242    #endif
243    
244    #if USE_GTKMM_BUILDER
245        uiManager = Gtk::Builder::create();
246        Glib::ustring ui_info =
247            "<interface>"
248            "  <menu id='menu-PopupMenuInsideDimRegion'>"
249            "    <section>"
250            "      <item id='item-split'>"
251            "        <attribute name='label' translatable='yes'>Split Dimensions Zone</attribute>"
252            "        <attribute name='action'>PopupMenuInsideDimRegion.SplitDimZone</attribute>"
253            "      </item>"
254            "      <item id='item-delete'>"
255            "        <attribute name='label' translatable='yes'>Delete Dimension Zone</attribute>"
256            "        <attribute name='action'>PopupMenuInsideDimRegion.DeleteDimZone</attribute>"
257            "      </item>"
258            "    </section>"
259            "  </menu>"
260            "</interface>";
261        uiManager->add_from_string(ui_info);
262    
263        popup_menu_inside_dimregion = new Gtk::Menu(
264            Glib::RefPtr<Gio::Menu>::cast_dynamic(
265                uiManager->get_object("menu-PopupMenuInsideDimRegion")
266            )
267        );
268    #else
269        uiManager = Gtk::UIManager::create();
270        uiManager->insert_action_group(actionGroup);
271        Glib::ustring ui_info =
272            "<ui>"
273            "  <popup name='PopupMenuInsideDimRegion'>"
274            "    <menuitem action='SplitDimZone'/>"
275            "    <menuitem action='DeleteDimZone'/>"
276            "  </popup>"
277    //         "  <popup name='PopupMenuOutsideDimRegion'>"
278    //         "    <menuitem action='Add'/>"
279    //         "  </popup>"
280            "</ui>";
281        uiManager->add_ui_from_string(ui_info);
282    
283        popup_menu_inside_dimregion = dynamic_cast<Gtk::Menu*>(
284            uiManager->get_widget("/PopupMenuInsideDimRegion"));
285    //     popup_menu_outside_dimregion = dynamic_cast<Gtk::Menu*>(
286    //         uiManager->get_widget("/PopupMenuOutsideDimRegion"));
287    
288    #endif // USE_GTKMM_BUILDER
289    
290    
291    #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION > 22)
292    # warning GTKMM4 event registration code missing for dimregionchooser!
293        //add_events(Gdk::EventMask::BUTTON_PRESS_MASK);
294    #else
295      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |      add_events(Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK |
296                 Gdk::POINTER_MOTION_HINT_MASK);                 Gdk::POINTER_MOTION_HINT_MASK);
297    #endif
298    
299        labels_changed = true;
300    
301      for (int i = 0 ; i < 256 ; i++) dimvalue[i] = 0;      set_tooltip_text(_(
302            "Right click here for options on altering dimension zones. Press and "
303            "hold CTRL key for selecting multiple dimension zones simultaniously."
304        ));
305        
306        window.signal_key_press_event().connect(
307            sigc::mem_fun(*this, &DimRegionChooser::onKeyPressed)
308        );
309        window.signal_key_release_event().connect(
310            sigc::mem_fun(*this, &DimRegionChooser::onKeyReleased)
311        );
312  }  }
313    
314  DimRegionChooser::~DimRegionChooser()  DimRegionChooser::~DimRegionChooser()
315  {  {
316  }  }
317    
318  void DimRegionChooser::on_realize()  void DimRegionChooser::setModifyBothChannels(bool b) {
319        modifybothchannels = b;
320        // redraw required parts
321        queue_draw();
322    }
323    
324    void DimRegionChooser::setModifyAllDimensionRegions(bool b) {
325        modifyalldimregs = b;
326        // redraw required parts
327        queue_draw();
328    }
329    
330    void DimRegionChooser::setModifyAllRegions(bool b) {
331        modifyallregions = b;
332    
333    #if USE_GTKMM_BUILDER
334        auto menuItemSplit = Glib::RefPtr<Gio::MenuItem>::cast_dynamic(
335            uiManager->get_object("item-split")
336        );
337        auto menuItemDelete = Glib::RefPtr<Gio::MenuItem>::cast_dynamic(
338            uiManager->get_object("item-delete")
339        );
340        menuItemDelete->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
341        menuItemSplit->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
342    #else
343        actionDeleteDimZone->set_label(b ? _("Delete Dimension Zone [ALL REGIONS]") : _("Delete Dimension Zone"));
344        actionSplitDimZone->set_label(b ? _("Split Dimensions Zone [ALL REGIONS]") : _("Split Dimensions Zone"));
345    #endif
346    
347        // redraw required parts
348        queue_draw();
349    }
350    
351    void DimRegionChooser::drawIconsFor(
352        gig::dimension_t dimension, uint zone,
353        const Cairo::RefPtr<Cairo::Context>& cr,
354        int x, int y, int w, int h)
355  {  {
356      // We need to call the base on_realize()      DimensionCase dimCase;
357      Gtk::DrawingArea::on_realize();      dimCase[dimension] = zone;
358    
359      // Now we can allocate any additional resources we need      std::vector<gig::DimensionRegion*> dimregs =
360      Glib::RefPtr<Gdk::Window> window = get_window();          dimensionRegionsMatching(dimCase, region, true);
361      gc = Gdk::GC::create(window);  
362        if (dimregs.empty()) return;
363    
364        int iSampleRefs = 0;
365        int iLoops = 0;
366    
367        for (uint i = 0; i < dimregs.size(); ++i) {
368            if (dimregs[i]->pSample) iSampleRefs++;
369            if (dimregs[i]->SampleLoops) iLoops++;
370        }
371    
372        bool bShowLoopSymbol = (iLoops > 0);
373        bool bShowSampleRefSymbol = (iSampleRefs < dimregs.size());
374    
375        if (bShowLoopSymbol || bShowSampleRefSymbol) {
376            const int margin = 1;
377    
378            cr->save();
379            cr->set_line_width(1);
380            cr->rectangle(x, y + margin, w, h - 2*margin);
381            cr->clip();
382            if (bShowSampleRefSymbol) {
383                const int wPic = 8;
384                const int hPic = 8;
385                Gdk::Cairo::set_source_pixbuf(
386                    cr, (iSampleRefs) ? yellowDot : redDot,
387                    x + (w-wPic)/2.f,
388                    y + (
389                        (bShowLoopSymbol) ? margin : (h-hPic)/2.f
390                    )
391                );
392                cr->paint();
393            }
394            if (bShowLoopSymbol) {
395                const int wPic = 12;
396                const int hPic = 14;
397                Gdk::Cairo::set_source_pixbuf(
398                    cr, (iLoops == dimregs.size()) ? blackLoop : grayLoop,
399                    x + (w-wPic)/2.f,
400                    y + (
401                        (bShowSampleRefSymbol) ? h - hPic - margin : (h-hPic)/2.f
402                    )
403                );
404                cr->paint();
405            }
406            cr->restore();
407        }
408  }  }
409    
410  bool DimRegionChooser::on_expose_event(GdkEventExpose* event)  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
411    bool DimRegionChooser::on_expose_event(GdkEventExpose* e)
412    {
413        double clipx1 = e->area.x;
414        double clipx2 = e->area.x + e->area.width;
415        double clipy1 = e->area.y;
416        double clipy2 = e->area.y + e->area.height;
417    
418        const Cairo::RefPtr<Cairo::Context>& cr =
419            get_window()->create_cairo_context();
420    #else
421    bool DimRegionChooser::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
422  {  {
423        double clipx1, clipx2, clipy1, clipy2;
424        cr->get_clip_extents(clipx1, clipy1, clipx2, clipy2);
425    #endif
426    
427      if (!region) return true;      if (!region) return true;
428    
429      // This is where we draw on the window      // This is where we draw on the window
430      int w = get_width();      int w = get_width();
     Glib::RefPtr<Gdk::Window> window = get_window();  
431      Glib::RefPtr<Pango::Context> context = get_pango_context();      Glib::RefPtr<Pango::Context> context = get_pango_context();
432    
433      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);      Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
434        cr->set_line_width(1);
435    
     window->clear();  
   
     // draw labels on the left (reflecting the dimension type)  
436      int y = 0;      int y = 0;
437      double maxwidth = 0;      if (labels_changed || label_width - 10 > clipx1) {
438      for (int i = 0 ; i < region->Dimensions ; i++) {          // draw labels on the left (reflecting the dimension type)
439          int nbZones = region->pDimensionDefinitions[i].zones;          double maxwidth = 0;
440          if (nbZones) {          for (int i = 0 ; i < region->Dimensions ; i++) {
441              const char* dstr;              int nbZones = region->pDimensionDefinitions[i].zones;
442              char dstrbuf[10];              if (nbZones) {
443              switch (region->pDimensionDefinitions[i].dimension) {                  const char* dstr;
444              case gig::dimension_none: dstr="none"; break;                  char dstrbuf[10];
445              case gig::dimension_samplechannel: dstr="samplechannel"; break;                  switch (region->pDimensionDefinitions[i].dimension) {
446              case gig::dimension_layer: dstr="layer"; break;                  case gig::dimension_none: dstr=_("none"); break;
447              case gig::dimension_velocity: dstr="velocity"; break;                  case gig::dimension_samplechannel: dstr=_("samplechannel");
448              case gig::dimension_channelaftertouch: dstr="channelaftertouch"; break;                      break;
449              case gig::dimension_releasetrigger: dstr="releasetrigger"; break;                  case gig::dimension_layer: dstr=_("layer"); break;
450              case gig::dimension_keyboard: dstr="keyswitching"; break;                  case gig::dimension_velocity: dstr=_("velocity"); break;
451              case gig::dimension_roundrobin: dstr="roundrobin"; break;                  case gig::dimension_channelaftertouch:
452              case gig::dimension_random: dstr="random"; break;                      dstr=_("channelaftertouch"); break;
453              case gig::dimension_smartmidi: dstr="smartmidi"; break;                  case gig::dimension_releasetrigger:
454              case gig::dimension_roundrobinkeyboard: dstr="roundrobinkeyboard"; break;                      dstr=_("releasetrigger"); break;
455              case gig::dimension_modwheel: dstr="modwheel"; break;                  case gig::dimension_keyboard: dstr=_("keyswitching"); break;
456              case gig::dimension_breath: dstr="breath"; break;                  case gig::dimension_roundrobin: dstr=_("roundrobin"); break;
457              case gig::dimension_foot: dstr="foot"; break;                  case gig::dimension_random: dstr=_("random"); break;
458              case gig::dimension_portamentotime: dstr="portamentotime"; break;                  case gig::dimension_smartmidi: dstr=_("smartmidi"); break;
459              case gig::dimension_effect1: dstr="effect1"; break;                  case gig::dimension_roundrobinkeyboard:
460              case gig::dimension_effect2: dstr="effect2"; break;                      dstr=_("roundrobinkeyboard"); break;
461              case gig::dimension_genpurpose1: dstr="genpurpose1"; break;                  case gig::dimension_modwheel: dstr=_("modwheel"); break;
462              case gig::dimension_genpurpose2: dstr="genpurpose2"; break;                  case gig::dimension_breath: dstr=_("breath"); break;
463              case gig::dimension_genpurpose3: dstr="genpurpose3"; break;                  case gig::dimension_foot: dstr=_("foot"); break;
464              case gig::dimension_genpurpose4: dstr="genpurpose4"; break;                  case gig::dimension_portamentotime:
465              case gig::dimension_sustainpedal: dstr="sustainpedal"; break;                      dstr=_("portamentotime"); break;
466              case gig::dimension_portamento: dstr="portamento"; break;                  case gig::dimension_effect1: dstr=_("effect1"); break;
467              case gig::dimension_sostenutopedal: dstr="sostenutopedal"; break;                  case gig::dimension_effect2: dstr=_("effect2"); break;
468              case gig::dimension_softpedal: dstr="softpedal"; break;                  case gig::dimension_genpurpose1: dstr=_("genpurpose1"); break;
469              case gig::dimension_genpurpose5: dstr="genpurpose5"; break;                  case gig::dimension_genpurpose2: dstr=_("genpurpose2"); break;
470              case gig::dimension_genpurpose6: dstr="genpurpose6"; break;                  case gig::dimension_genpurpose3: dstr=_("genpurpose3"); break;
471              case gig::dimension_genpurpose7: dstr="genpurpose7"; break;                  case gig::dimension_genpurpose4: dstr=_("genpurpose4"); break;
472              case gig::dimension_genpurpose8: dstr="genpurpose8"; break;                  case gig::dimension_sustainpedal:
473              case gig::dimension_effect1depth: dstr="effect1depth"; break;                      dstr=_("sustainpedal"); break;
474              case gig::dimension_effect2depth: dstr="effect2depth"; break;                  case gig::dimension_portamento: dstr=_("portamento"); break;
475              case gig::dimension_effect3depth: dstr="effect3depth"; break;                  case gig::dimension_sostenutopedal:
476              case gig::dimension_effect4depth: dstr="effect4depth"; break;                      dstr=_("sostenutopedal"); break;
477              case gig::dimension_effect5depth: dstr="effect5depth"; break;                  case gig::dimension_softpedal: dstr=_("softpedal"); break;
478              default:                  case gig::dimension_genpurpose5: dstr=_("genpurpose5"); break;
479                  sprintf(dstrbuf, "%d",                  case gig::dimension_genpurpose6: dstr=_("genpurpose6"); break;
480                          region->pDimensionDefinitions[i].dimension);                  case gig::dimension_genpurpose7: dstr=_("genpurpose7"); break;
481                  dstr = dstrbuf;                  case gig::dimension_genpurpose8: dstr=_("genpurpose8"); break;
482                  break;                  case gig::dimension_effect1depth:
483              }                      dstr=_("effect1depth"); break;
484              layout->set_text(dstr);                  case gig::dimension_effect2depth:
485                        dstr=_("effect2depth"); break;
486              Pango::Rectangle rectangle = layout->get_logical_extents();                  case gig::dimension_effect3depth:
487              double text_w = double(rectangle.get_width()) / Pango::SCALE;                      dstr=_("effect3depth"); break;
488              if (text_w > maxwidth) maxwidth = text_w;                  case gig::dimension_effect4depth:
489              double text_h = double(rectangle.get_height()) / Pango::SCALE;                      dstr=_("effect4depth"); break;
490              Glib::RefPtr<const Gdk::GC> fg = get_style()->get_fg_gc(get_state());                  case gig::dimension_effect5depth:
491              window->draw_layout(fg, 4, int(y + (h - text_h) / 2 + 0.5), layout);                      dstr=_("effect5depth"); break;
492                    default:
493                        sprintf(dstrbuf, "%d",
494                                region->pDimensionDefinitions[i].dimension);
495                        dstr = dstrbuf;
496                        break;
497                    }
498    
499                    // Since bold font yields in larger label width, we first always
500                    // set the bold text variant, retrieve its dimensions (as worst
501                    // case dimensions of the label) ...
502                    layout->set_markup("<b>" + Glib::ustring(dstr) + "</b>");
503                    Pango::Rectangle rectangle = layout->get_logical_extents();
504                    // ... and then reset the label to regular font style in case
505                    // the line is not selected. Otherwise the right hand side
506                    // actual dimension zones would jump around on selection change.
507                    bool isSelectedLine = (focus_line == i);
508                    if (!isSelectedLine)
509                        layout->set_markup(dstr);
510    
511                    double text_w = double(rectangle.get_width()) / Pango::SCALE;
512                    if (text_w > maxwidth) maxwidth = text_w;
513    
514                    if (y + h > clipy1 && y < clipy2 && text_w >= clipx1) {
515                        double text_h = double(rectangle.get_height()) /
516                            Pango::SCALE;
517    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
518                        const Gdk::Color fg = get_style()->get_fg(get_state());
519    #else
520                        const Gdk::RGBA fg =
521    # if GTKMM_MAJOR_VERSION >= 3
522                            get_style_context()->get_color();
523    # else
524                            get_style_context()->get_color(get_state_flags());
525    # endif
526    #endif
527                        Gdk::Cairo::set_source_rgba(cr, fg);
528                        cr->move_to(4, int(y + (h - text_h) / 2 + 0.5));
529    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
530                        pango_cairo_show_layout(cr->cobj(), layout->gobj());
531    #else
532                        layout->show_in_cairo_context(cr);
533    #endif
534                    }
535                }
536                y += h;
537          }          }
538          y += h;          label_width = int(maxwidth + 10);
539            labels_changed = false;
540      }      }
541        if (label_width >= clipx2) return true;
542    
543      // draw dimensions' zones areas      // draw dimensions' zones areas
544      y = 0;      y = 0;
545      int bitpos = 0;      int bitpos = 0;
     label_width = int(maxwidth + 10);  
546      for (int i = 0 ; i < region->Dimensions ; i++) {      for (int i = 0 ; i < region->Dimensions ; i++) {
547          int nbZones = region->pDimensionDefinitions[i].zones;          int nbZones = region->pDimensionDefinitions[i].zones;
548          if (nbZones) {          if (nbZones) {
549              // 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));  
550    
551              // draw dimension's zone borders              if (y >= clipy2) break;
552              if (customsplits) {              if (y + h > clipy1) {
553                  window->draw_line(black, label_width, y + 1, label_width, y + h - 2);                  // draw focus rectangle around dimension's label and zones
554                  for (int j = 0 ; j < nbZones ; j++) {                  if (has_focus() && focus_line == i) {
555                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
556                      int upperLimit = d->DimensionUpperLimits[i];                      Gdk::Rectangle farea(0, y, 150, h);
557                      if (!upperLimit) upperLimit = d->VelocityUpperLimit;                      get_style()->paint_focus(get_window(), get_state(), farea,
558                      int v = upperLimit + 1;                                               *this, "",
559                      int x = int((w - label_width - 1) * v / 128.0 + 0.5);                                               0, y, label_width, h);
560                      window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);  #else
561                        get_style_context()->render_focus(cr,
562                                                          0, y, label_width, h);
563    #endif
564                  }                  }
565              } else {  
566                  for (int j = 0 ; j <= nbZones ; j++) {                  // draw top and bottom lines of dimension's zones
567                      int x = int((w - label_width - 1) * j / double(nbZones) + 0.5);                  Gdk::Cairo::set_source_rgba(cr, black);
568                      window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);                  cr->move_to(label_width, y + 0.5);
569                    cr->line_to(w, y + 0.5);
570                    cr->move_to(w, y + h - 0.5);
571                    cr->line_to(label_width, y + h - 0.5);
572                    cr->stroke();
573    
574                    // erase whole dimension's zones area
575                    Gdk::Cairo::set_source_rgba(cr, white);
576                    cr->rectangle(label_width + 1, y + 1,
577                                  (w - label_width - 2), h - 2);
578                    cr->fill();
579    
580                    int c = 0;
581                    if (maindimregno >= 0) {
582                        int mask =
583                            ~(((1 << region->pDimensionDefinitions[i].bits) - 1) <<
584                              bitpos);
585                        c = maindimregno & mask; // mask away this dimension
586                  }                  }
587              }                  bool customsplits =
588                        ((region->pDimensionDefinitions[i].split_type ==
589                          gig::split_type_normal &&
590                          region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
591                         (region->pDimensionDefinitions[i].dimension ==
592                          gig::dimension_velocity &&
593                          region->pDimensionRegions[c]->VelocityUpperLimit));
594    
595              // draw fill for currently selected zone                  // draw dimension zones
596              if (dimregno >= 0) {                  Gdk::Cairo::set_source_rgba(cr, black);
                 gc->set_foreground(red);  
                 int dr = (dimregno >> bitpos) & ((1 << region->pDimensionDefinitions[i].bits) - 1);  
597                  if (customsplits) {                  if (customsplits) {
598                      int x1 = 0;                      cr->move_to(label_width + 0.5, y + 1);
599                        cr->line_to(label_width + 0.5, y + h - 1);
600                        int prevX = label_width;
601                        int prevUpperLimit = -1;
602    
603                      for (int j = 0 ; j < nbZones ; j++) {                      for (int j = 0 ; j < nbZones ; j++) {
604                          gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];                          // draw dimension zone's borders for custom splits
605                            gig::DimensionRegion* d =
606                                region->pDimensionRegions[c + (j << bitpos)];
607                          int upperLimit = d->DimensionUpperLimits[i];                          int upperLimit = d->DimensionUpperLimits[i];
608                          if (!upperLimit) upperLimit = d->VelocityUpperLimit;                          if (!upperLimit) upperLimit = d->VelocityUpperLimit;
609                          int v = upperLimit + 1;                          int v = upperLimit + 1;
610                          int x2 = int((w - label_width - 1) * v / 128.0 + 0.5);                          int x = int((w - label_width - 1) * v / 128.0 + 0.5) +
611                          if (j == dr && x1 < x2) {                              label_width;
612                              window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,                          if (x >= clipx2) break;
613                                                     (x2 - x1) - 1, h - 2);                          if (x < clipx1) continue;
614                              break;                          Gdk::Cairo::set_source_rgba(cr, black);
615                            cr->move_to(x + 0.5, y + 1);
616                            cr->line_to(x + 0.5, y + h - 1);
617                            cr->stroke();
618    
619                            // draw fill for zone
620                            bool isSelectedZone = this->dimzones[dimension].count(j);
621                            bool isMainSelection =
622                                this->maindimcase.find(dimension) != this->maindimcase.end() &&
623                                this->maindimcase[dimension] == j;
624                            bool isCheckBoxSelected =
625                                modifyalldimregs ||
626                                (modifybothchannels &&
627                                    dimension == gig::dimension_samplechannel);
628                            if (isMainSelection)
629                                Gdk::Cairo::set_source_rgba(cr, blue);
630                            else if (isSelectedZone)
631                                cr->set_source(blueHatchedSurfacePattern2);
632                            else if (isCheckBoxSelected)
633                                cr->set_source(blueHatchedSurfacePattern);
634                            else
635                                Gdk::Cairo::set_source_rgba(cr, white);
636    
637                            const int wZone = x - prevX - 1;
638    
639                            cr->rectangle(prevX + 1, y + 1, wZone, h - 1);
640                            cr->fill();
641    
642                            // draw icons
643                            drawIconsFor(dimension, j, cr, prevX, y, wZone, h);
644    
645                            // draw text showing the beginning of the dimension zone
646                            // as numeric value to the user
647                            {
648                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
649                                layout->set_text(Glib::Ascii::dtostr(prevUpperLimit+1));
650                                Gdk::Cairo::set_source_rgba(cr, black);
651                                // get the text dimensions
652                                int text_width, text_height;
653                                layout->get_pixel_size(text_width, text_height);
654                                // move text to the left end of the dimension zone
655                                cr->move_to(prevX + 3, y + (h - text_height) / 2);
656    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
657                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
658    #else
659                                layout->show_in_cairo_context(cr);
660    #endif
661                            }
662                            // draw text showing the end of the dimension zone
663                            // as numeric value to the user
664                            {
665                                Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
666                                layout->set_text(Glib::Ascii::dtostr(upperLimit));
667                                Gdk::Cairo::set_source_rgba(cr, black);
668                                // get the text dimensions
669                                int text_width, text_height;
670                                layout->get_pixel_size(text_width, text_height);
671                                // move text to the left end of the dimension zone
672                                cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
673    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
674                                pango_cairo_show_layout(cr->cobj(), layout->gobj());
675    #else
676                                layout->show_in_cairo_context(cr);
677    #endif
678                          }                          }
679                          x1 = x2;  
680                            prevX = x;
681                            prevUpperLimit = upperLimit;
682                      }                      }
683                  } else {                  } else {
684                      if (dr < nbZones) {                      int prevX = 0;
685                          int x1 = int((w - label_width - 1) * dr / double(nbZones) + 0.5);                      for (int j = 0 ; j <= nbZones ; j++) {
686                          int x2 = int((w - label_width - 1) * (dr + 1) / double(nbZones) + 0.5);                          // draw dimension zone's borders for normal splits
687                          window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,                          int x = int((w - label_width - 1) * j /
688                                                 (x2 - x1) - 1, h - 2);                                      double(nbZones) + 0.5) + label_width;
689                      }                          if (x >= clipx2) break;
690                            if (x < clipx1) continue;
691                            Gdk::Cairo::set_source_rgba(cr, black);
692                            cr->move_to(x + 0.5, y + 1);
693                            cr->line_to(x + 0.5, y + h - 1);
694                            cr->stroke();
695    
696                            if (j != 0) {
697                                const int wZone = x - prevX - 1;
698    
699                                // draw fill for zone
700                                bool isSelectedZone = this->dimzones[dimension].count(j-1);
701                                bool isMainSelection =
702                                    this->maindimcase.find(dimension) != this->maindimcase.end() &&
703                                    this->maindimcase[dimension] == (j-1);
704                                bool isCheckBoxSelected =
705                                    modifyalldimregs ||
706                                    (modifybothchannels &&
707                                        dimension == gig::dimension_samplechannel);
708                                if (isMainSelection)
709                                    Gdk::Cairo::set_source_rgba(cr, blue);
710                                else if (isSelectedZone)
711                                    cr->set_source(blueHatchedSurfacePattern2);
712                                else if (isCheckBoxSelected)
713                                    cr->set_source(blueHatchedSurfacePattern);
714                                else
715                                    Gdk::Cairo::set_source_rgba(cr, white);
716                                cr->rectangle(prevX + 1, y + 1, wZone, h - 1);
717                                cr->fill();
718    
719                                // draw icons
720                                drawIconsFor(dimension, j - 1, cr, prevX, y, wZone, h);
721    
722                                // draw text showing the beginning of the dimension zone
723                                // as numeric value to the user
724                                {
725                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
726                                    layout->set_text(Glib::Ascii::dtostr((j-1) * 128/nbZones));
727                                    Gdk::Cairo::set_source_rgba(cr, black);
728                                    // get the text dimensions
729                                    int text_width, text_height;
730                                    layout->get_pixel_size(text_width, text_height);
731                                    // move text to the left end of the dimension zone
732                                    cr->move_to(prevX + 3, y + (h - text_height) / 2);
733    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
734                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
735    #else
736                                    layout->show_in_cairo_context(cr);
737    #endif
738                                }
739                                // draw text showing the end of the dimension zone
740                                // as numeric value to the user
741                                {
742                                    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);
743                                    layout->set_text(Glib::Ascii::dtostr(j * 128/nbZones - 1));
744                                    Gdk::Cairo::set_source_rgba(cr, black);
745                                    // get the text dimensions
746                                    int text_width, text_height;
747                                    layout->get_pixel_size(text_width, text_height);
748                                    // move text to the left end of the dimension zone
749                                    cr->move_to(x - 3 - text_width, y + (h - text_height) / 2);
750    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 16) || GTKMM_MAJOR_VERSION < 2
751                                    pango_cairo_show_layout(cr->cobj(), layout->gobj());
752    #else
753                                    layout->show_in_cairo_context(cr);
754    #endif
755                                }
756                            }
757                            prevX = x;
758                        }      
759                  }                  }
760              }              }
   
761              y += h;              y += h;
762          }          }
763          bitpos += region->pDimensionDefinitions[i].bits;          bitpos += region->pDimensionDefinitions[i].bits;
# Line 228  bool DimRegionChooser::on_expose_event(G Line 766  bool DimRegionChooser::on_expose_event(G
766      return true;      return true;
767  }  }
768    
 void DimRegionChooser::on_size_request(GtkRequisition* requisition)  
 {  
     *requisition = GtkRequisition();  
     requisition->height = region ? nbDimensions * 20 : 0;  
     requisition->width = 800;  
 }  
   
769  void DimRegionChooser::set_region(gig::Region* region)  void DimRegionChooser::set_region(gig::Region* region)
770  {  {
771      this->region = region;      this->region = region;
772      dimregno = 0;      maindimregno = 0;
773      nbDimensions = 0;      nbDimensions = 0;
774      if (region) {      if (region) {
775          int bitcount = 0;          int bitcount = 0;
# Line 246  void DimRegionChooser::set_region(gig::R Line 777  void DimRegionChooser::set_region(gig::R
777              if (region->pDimensionDefinitions[dim].bits == 0) continue;              if (region->pDimensionDefinitions[dim].bits == 0) continue;
778              nbDimensions++;              nbDimensions++;
779    
780              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              int z = std::min(maindimcase[region->pDimensionDefinitions[dim].dimension],
781                               region->pDimensionDefinitions[dim].zones - 1);                               region->pDimensionDefinitions[dim].zones - 1);
782              dimregno |= (z << bitcount);              maindimregno |= (z << bitcount);
783              bitcount += region->pDimensionDefinitions[dim].bits;              bitcount += region->pDimensionDefinitions[dim].bits;
784          }          }
         dimreg = region->pDimensionRegions[dimregno];  
     } else {  
         dimreg = 0;  
785      }      }
786      dimregion_selected();      dimregion_selected();
787        set_size_request(800, region ? nbDimensions * h : 0);
788    
789        labels_changed = true;
790      queue_resize();      queue_resize();
791        queue_draw();
792  }  }
793    
794    void DimRegionChooser::refresh_all() {
795        set_region(region);
796    }
797    
798  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,  void DimRegionChooser::get_dimregions(const gig::Region* region, bool stereo,
799                                        std::set<gig::DimensionRegion*>& dimregs) const                                        std::set<gig::DimensionRegion*>& dimregs) const
800  {  {
801      int dimregno = 0;      for (int iDimRgn = 0; iDimRgn < 256; ++iDimRgn) {
802      int bitcount = 0;          gig::DimensionRegion* dimRgn = region->pDimensionRegions[iDimRgn];
803      int stereo_bit = 0;          if (!dimRgn) continue;
804      for (int dim = 0 ; dim < region->Dimensions ; dim++) {          bool isValidZone;
805          if (region->pDimensionDefinitions[dim].bits == 0) continue;          std::map<gig::dimension_t,int> dimCase = caseOfDimRegion(dimRgn, &isValidZone);
806          if (stereo &&          if (!isValidZone) continue;
807              region->pDimensionDefinitions[dim].dimension == gig::dimension_samplechannel) {          for (std::map<gig::dimension_t,int>::const_iterator it = dimCase.begin();
808              stereo_bit = (1 << bitcount);               it != dimCase.end(); ++it)
809          } else {          {
810              int z = std::min(dimvalue[region->pDimensionDefinitions[dim].dimension],              if (stereo && it->first == gig::dimension_samplechannel) continue; // is selected
811                               region->pDimensionDefinitions[dim].zones - 1);  
812              dimregno |= (z << bitcount);              std::map<gig::dimension_t, std::set<int> >::const_iterator itSelectedDimension =
813                    this->dimzones.find(it->first);
814                if (itSelectedDimension != this->dimzones.end() &&
815                    itSelectedDimension->second.count(it->second)) continue; // is selected
816    
817                goto notSelected;
818          }          }
819          bitcount += region->pDimensionDefinitions[dim].bits;  
820            dimregs.insert(dimRgn);
821    
822            notSelected:
823            ;
824      }      }
     dimregs.insert(region->pDimensionRegions[dimregno]);  
     if (stereo_bit) dimregs.insert(region->pDimensionRegions[dimregno | stereo_bit]);  
825  }  }
826    
827    void DimRegionChooser::update_after_resize()
 bool DimRegionChooser::on_button_release_event(GdkEventButton* event)  
828  {  {
829      if (resize.active) {      const uint8_t upperLimit = resize.pos - 1;
830          get_window()->pointer_ungrab(event->time);      gig::Instrument* instr = (gig::Instrument*)region->GetParent();
         resize.active = false;  
831    
832          if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {      int bitpos = 0;
833        for (int j = 0 ; j < resize.dimension ; j++) {
834            bitpos += region->pDimensionDefinitions[j].bits;
835        }
836    
837              int bitpos = 0;      const int stereobitpos =
838              for (int j = 0 ; j < resize.dimension ; j++) {          (modifybothchannels) ? baseBits(gig::dimension_samplechannel, region) : -1;
839                  bitpos += region->pDimensionDefinitions[j].bits;  
840        // the velocity dimension must be handled differently than all other
841        // dimension types, because
842        // 1. it is currently the only dimension type which allows different zone
843        //    sizes for different cases
844        // 2. for v2 format VelocityUpperLimit has to be set, DimensionUpperLimits for v3
845        if (region->pDimensionDefinitions[resize.dimension].dimension == gig::dimension_velocity) {
846            int mask =
847                ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);
848            int c = maindimregno & mask; // mask away this dimension
849    
850            if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {
851                // the velocity dimension didn't previously have
852                // custom v3 splits, so we initialize all splits with
853                // default values
854                int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
855                for (int j = 0 ; j < nbZones ; j++) {
856                    gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
857                    d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
858              }              }
859              int mask =          }
860                  ~(((1 << region->pDimensionDefinitions[resize.dimension].bits) - 1) << bitpos);          if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {
861              int c = dimregno & mask; // mask away this dimension              // the velocity dimension didn't previously have
862                // custom v2 splits, so we initialize all splits with
863              if (region->pDimensionRegions[c]->DimensionUpperLimits[resize.dimension] == 0) {              // default values
864                  // the velocity dimension didn't previously have              int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
865                  // custom v3 splits, so we initialize all splits with              for (int j = 0 ; j < nbZones ; j++) {
866                  // default values                  gig::DimensionRegion* d = region->pDimensionRegions[c + (j << bitpos)];
867                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);
868                  for (int j = 0 ; j < nbZones ; j++) {              }
869                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];          }
870                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);  
871            int index = c + (resize.zone << bitpos);
872            gig::DimensionRegion* d = region->pDimensionRegions[index];
873            // update both v2 and v3 values
874            d->DimensionUpperLimits[resize.dimension] = upperLimit;
875            d->VelocityUpperLimit = upperLimit;
876            if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
877                gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
878                d->DimensionUpperLimits[resize.dimension] = upperLimit;
879                d->VelocityUpperLimit = upperLimit;
880            }
881    
882            if (modifyalldimregs) {
883                gig::Region* rgn = NULL;
884                for (int key = 0; key < 128; ++key) {
885                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
886                    rgn = instr->GetRegion(key);
887                    if (!modifyallregions && rgn != region) continue; // hack to reduce overall code amount a bit
888                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
889                    if (!dimdef) continue;
890                    if (dimdef->zones != resize.dimensionDef.zones) continue;
891                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
892                    assert(iDim >= 0 && iDim < rgn->Dimensions);
893    
894                    // the dimension layout might be completely different in this
895                    // region, so we have to recalculate bitpos etc for this region
896                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
897                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
898                    const int selection = resize.zone << bitpos;
899    
900                    // primitive and inefficient loop implementation, however due to
901                    // this circumstance the loop code is much simpler, and its lack
902                    // of runtime efficiency should not be notable in practice
903                    for (int idr = 0; idr < 256; ++idr) {
904                        const int index = (idr & stencil) | selection;
905                        assert(index >= 0 && index < 256);
906                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
907                        if (!dr) continue;
908                        dr->DimensionUpperLimits[iDim] = upperLimit;
909                        d->VelocityUpperLimit = upperLimit;
910                    }
911                }
912            } else if (modifyallregions) { // implies modifyalldimregs is false ...
913                // resolve the precise case we need to modify for all other regions
914                DimensionCase dimCase = dimensionCaseOf(d);
915                // apply the velocity upper limit change to that resolved dim case
916                // of all regions ...
917                gig::Region* rgn = NULL;
918                for (int key = 0; key < 128; ++key) {
919                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
920                    rgn = instr->GetRegion(key);
921                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
922                    if (!dimdef) continue;
923                    if (dimdef->zones != resize.dimensionDef.zones) continue;
924                    const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
925                    assert(iDim >= 0 && iDim < rgn->Dimensions);
926    
927                    std::vector<gig::DimensionRegion*> dimrgns = dimensionRegionsMatching(dimCase, rgn);
928                    for (int i = 0; i < dimrgns.size(); ++i) {
929                        gig::DimensionRegion* dr = dimrgns[i];
930                        dr->DimensionUpperLimits[iDim] = upperLimit;
931                        dr->VelocityUpperLimit = upperLimit;
932                  }                  }
933              }              }
934              if (region->pDimensionRegions[c]->VelocityUpperLimit == 0) {          }
935                  // the velocity dimension didn't previously have      } else {
936                  // custom v2 splits, so we initialize all splits with          for (int i = 0 ; i < region->DimensionRegions ; ) {
937                  // default values              if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {
938                    // the dimension didn't previously have custom
939                    // limits, so we have to set default limits for
940                    // all the dimension regions
941                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;                  int nbZones = region->pDimensionDefinitions[resize.dimension].zones;
942    
943                  for (int j = 0 ; j < nbZones ; j++) {                  for (int j = 0 ; j < nbZones ; j++) {
944                      gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];                      gig::DimensionRegion* d = region->pDimensionRegions[i + (j << bitpos)];
945                      d->VelocityUpperLimit = int(128.0 * (j + 1) / nbZones - 1);                      d->DimensionUpperLimits[resize.dimension] = int(128.0 * (j + 1) / nbZones - 1);
946                  }                  }
947              }              }
948                int index = i + (resize.zone << bitpos);
949              gig::DimensionRegion *d = region->pDimensionRegions[c + resize.offset];              gig::DimensionRegion* d = region->pDimensionRegions[index];
950              // update both v2 and v3 values              d->DimensionUpperLimits[resize.dimension] = upperLimit;
951              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
952              d->VelocityUpperLimit = resize.pos - 1;              if (modifybothchannels && stereobitpos >= 0) { // do the same for the other audio channel's dimregion ...
953                    gig::DimensionRegion* d = region->pDimensionRegions[index ^ (1 << stereobitpos)];
954          } else {                  d->DimensionUpperLimits[resize.dimension] = upperLimit;
955              for (int i = 0 ; i < region->DimensionRegions ; ) {              }
956    #endif
957                  if (region->pDimensionRegions[i]->DimensionUpperLimits[resize.dimension] == 0) {              int bitpos = 0;
958                      // the dimension didn't previously have custom              int j;
959                      // limits, so we have to set default limits for              for (j = 0 ; j < region->Dimensions ; j++) {
960                      // all the dimension regions                  if (j != resize.dimension) {
961                      int bitpos = 0;                      int maxzones = 1 << region->pDimensionDefinitions[j].bits;
962                      for (int j = 0 ; j < resize.dimension ; j++) {                      int dimj = (i >> bitpos) & (maxzones - 1);
963                          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);  
                     }  
964                  }                  }
965                  gig::DimensionRegion *d = region->pDimensionRegions[i + resize.offset];                  bitpos += region->pDimensionDefinitions[j].bits;
966                  d->DimensionUpperLimits[resize.dimension] = resize.pos - 1;              }
967                if (j == region->Dimensions) break;
968                i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);
969            }
970    
971                  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
972                  int j;              gig::Region* rgn = NULL;
973                  for (j = 0 ; j < region->Dimensions ; j++) {              for (int key = 0; key < 128; ++key) {
974                      if (j != resize.dimension) {                  if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
975                          int maxzones = 1 << region->pDimensionDefinitions[j].bits;                  rgn = instr->GetRegion(key);
976                          int dimj = (i >> bitpos) & (maxzones - 1);                  gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(resize.dimensionDef.dimension);
977                          if (dimj + 1 < region->pDimensionDefinitions[j].zones) break;                  if (!dimdef) continue;
978                      }                  if (dimdef->zones != resize.dimensionDef.zones) continue;
979                      bitpos += region->pDimensionDefinitions[j].bits;                  const int iDim = getDimensionIndex(resize.dimensionDef.dimension, rgn);
980                    assert(iDim >= 0 && iDim < rgn->Dimensions);
981    
982                    // the dimension layout might be completely different in this
983                    // region, so we have to recalculate bitpos etc for this region
984                    const int bitpos = baseBits(resize.dimensionDef.dimension, rgn);
985                    const int stencil = ~(((1 << dimdef->bits) - 1) << bitpos);
986                    const int selection = resize.zone << bitpos;
987    
988                    // this loop implementation is less efficient than the above's
989                    // loop implementation (which skips unnecessary dimension regions)
990                    // however this code is much simpler, and its lack of runtime
991                    // efficiency should not be notable in practice
992                    for (int idr = 0; idr < 256; ++idr) {
993                        const int index = (idr & stencil) | selection;
994                        assert(index >= 0 && index < 256);
995                        gig::DimensionRegion* dr = rgn->pDimensionRegions[index];
996                        if (!dr) continue;
997                        dr->DimensionUpperLimits[iDim] = upperLimit;
998                  }                  }
                 if (j == region->Dimensions) break;  
                 i = (i & ~((1 << bitpos) - 1)) + (1 << bitpos);  
999              }              }
1000          }          }
1001        }
1002    }
1003    
1004    bool DimRegionChooser::on_button_release_event(GdkEventButton* event)
1005    {
1006        if (resize.active) {
1007    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1008            get_window()->pointer_ungrab(event->time);
1009    #else
1010    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1011            Glib::wrap(event->device, true)->ungrab(event->time);
1012    # else
1013            gdk_device_ungrab(Glib::wrap(event->device, true)->gobj(), event->time);
1014    # endif
1015    #endif
1016            resize.active = false;
1017    
1018          region_changed();          region_changed();
1019    
1020          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 1032  bool DimRegionChooser::on_button_press_e
1032          event->x >= label_width && event->x < w) {          event->x >= label_width && event->x < w) {
1033    
1034          if (is_in_resize_zone(event->x, event->y)) {          if (is_in_resize_zone(event->x, event->y)) {
1035              Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1036              get_window()->pointer_grab(false,              get_window()->pointer_grab(false,
1037                                         Gdk::BUTTON_RELEASE_MASK |                                         Gdk::BUTTON_RELEASE_MASK |
1038                                         Gdk::POINTER_MOTION_MASK |                                         Gdk::POINTER_MOTION_MASK |
1039                                         Gdk::POINTER_MOTION_HINT_MASK,                                         Gdk::POINTER_MOTION_HINT_MASK,
1040                                         double_arrow, event->time);                                         Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW),
1041                                           event->time);
1042    #else
1043    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1044                Glib::wrap(event->device, true)->grab(get_window(),
1045                                                      Gdk::OWNERSHIP_NONE,
1046                                                      false,
1047                                                      Gdk::BUTTON_RELEASE_MASK |
1048                                                      Gdk::POINTER_MOTION_MASK |
1049                                                      Gdk::POINTER_MOTION_HINT_MASK,
1050                                                      Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW),
1051                                                      event->time);
1052    # else
1053                gdk_device_grab(
1054                    Glib::wrap(event->device, true)->gobj(),
1055                    get_window()->gobj(),
1056                    GDK_OWNERSHIP_NONE,
1057                    false,
1058                    GdkEventMask(GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
1059                                 GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK),
1060                    Gdk::Cursor::create(
1061                        Glib::wrap(event->device, true)->get_seat()->get_display(),
1062                        Gdk::SB_H_DOUBLE_ARROW
1063                    )->gobj(),
1064                    event->time
1065                );
1066    # endif
1067    #endif
1068              resize.active = true;              resize.active = true;
1069          } else {          } else {
1070              int ydim = int(event->y / h);              int ydim = int(event->y / h);
# Line 401  bool DimRegionChooser::on_button_press_e Line 1083  bool DimRegionChooser::on_button_press_e
1083              }              }
1084    
1085              int i = dim;              int i = dim;
1086              if (dimregno < 0) dimregno = 0;              if (maindimregno < 0) maindimregno = 0;
1087              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
1088              int c = dimregno & mask; // mask away this dimension              int c = this->maindimregno & mask; // mask away this dimension
1089    
1090              bool customsplits =              bool customsplits =
1091                  ((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 1097  bool DimRegionChooser::on_button_press_e
1097    
1098                  if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {                  if (region->pDimensionRegions[c]->DimensionUpperLimits[i]) {
1099                      for (z = 0 ; z < nbZones ; z++) {                      for (z = 0 ; z < nbZones ; z++) {
1100                          gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];                          gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
1101                          if (val <= d->DimensionUpperLimits[i]) break;                          if (val <= d->DimensionUpperLimits[i]) break;
1102                      }                      }
1103                  } else {                  } else {
1104                      for (z = 0 ; z < nbZones ; z++) {                      for (z = 0 ; z < nbZones ; z++) {
1105                          gig::DimensionRegion *d = region->pDimensionRegions[c + (z << bitpos)];                          gig::DimensionRegion* d = region->pDimensionRegions[c + (z << bitpos)];
1106                          if (val <= d->VelocityUpperLimit) break;                          if (val <= d->VelocityUpperLimit) break;
1107                      }                      }
1108                  }                  }
# Line 433  bool DimRegionChooser::on_button_press_e Line 1115  bool DimRegionChooser::on_button_press_e
1115                     region->pDimensionDefinitions[dim].split_type,                     region->pDimensionDefinitions[dim].split_type,
1116                     region->pDimensionDefinitions[dim].zones,                     region->pDimensionDefinitions[dim].zones,
1117                     region->pDimensionDefinitions[dim].zone_size);                     region->pDimensionDefinitions[dim].zone_size);
1118              dimvalue[region->pDimensionDefinitions[dim].dimension] = z;              this->maindimcase[region->pDimensionDefinitions[dim].dimension] = z;
1119                this->maindimregno = c | (z << bitpos);
1120              dimregno = c | (z << bitpos);              this->maindimtype = region->pDimensionDefinitions[dim].dimension;
1121    
1122                if (multiSelectKeyDown) {
1123                    if (dimzones[this->maindimtype].count(z)) {
1124                        if (dimzones[this->maindimtype].size() > 1) {
1125                            dimzones[this->maindimtype].erase(z);
1126                        }
1127                    } else {
1128                        dimzones[this->maindimtype].insert(z);
1129                    }
1130                } else {
1131                    this->dimzones.clear();
1132                    for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1133                         it != this->maindimcase.end(); ++it)
1134                    {
1135                        this->dimzones[it->first].insert(it->second);
1136                    }
1137                }
1138    
1139              focus_line = dim;              focus_line = dim;
1140              if (has_focus()) queue_draw();              if (has_focus()) queue_draw();
1141              else grab_focus();              else grab_focus();
             dimreg = region->pDimensionRegions[dimregno];  
1142              dimregion_selected();              dimregion_selected();
1143    
1144                if (event->button == 3) {
1145                    printf("dimregion right click\n");
1146                    popup_menu_inside_dimregion->popup(event->button, event->time);
1147                }
1148    
1149                queue_draw();
1150          }          }
1151      }      }
1152      return true;      return true;
# Line 451  bool DimRegionChooser::on_motion_notify_ Line 1156  bool DimRegionChooser::on_motion_notify_
1156  {  {
1157      Glib::RefPtr<Gdk::Window> window = get_window();      Glib::RefPtr<Gdk::Window> window = get_window();
1158      int x, y;      int x, y;
1159    #if HAS_GDKMM_SEAT
1160        x = event->x;
1161        y = event->y;
1162        Gdk::ModifierType state = Gdk::ModifierType(event->state);
1163    #else
1164      Gdk::ModifierType state = Gdk::ModifierType(0);      Gdk::ModifierType state = Gdk::ModifierType(0);
1165      window->get_pointer(x, y, state);      window->get_pointer(x, y, state);
1166    #endif
1167    
1168      if (resize.active) {      if (resize.active) {
1169          int w = get_width();          int w = get_width();
# Line 464  bool DimRegionChooser::on_motion_notify_ Line 1175  bool DimRegionChooser::on_motion_notify_
1175          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
1176    
1177          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();  
   
1178              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;
1179              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;
1180              int y = resize.dimension * h;              int y = resize.dimension * h;
1181                int x1, x2;
1182              if (resize.selected == resize.none) {              if (k > resize.pos) {
1183                  if (resize.pos != resize.min && resize.pos != resize.max) {                  x1 = prevx;
1184                      window->draw_line(white, prevx, y + 1, prevx, y + h - 2);                  x2 = x;
                 }  
1185              } else {              } else {
1186                  gc->set_foreground(red);                  x1 = x;
1187                    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);  
                 }  
1188              }              }
1189              window->draw_line(black, x, y + 1, x, y + h - 2);              Gdk::Rectangle rect(x1, y + 1, x2 - x1 + 1, h - 2);
1190    
1191              resize.pos = k;              resize.pos = k;
1192                update_after_resize();
1193                get_window()->invalidate_rect(rect, false); // not sufficient ...
1194                queue_draw(); // ... so do a complete redraw instead.
1195          }          }
1196      } else {      } else {
1197          if (is_in_resize_zone(x, y)) {          if (is_in_resize_zone(x, y)) {
1198              if (!cursor_is_resize) {              if (!cursor_is_resize) {
1199                  Gdk::Cursor double_arrow(Gdk::SB_H_DOUBLE_ARROW);  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
1200                  window->set_cursor(double_arrow);                  window->set_cursor(Gdk::Cursor(Gdk::SB_H_DOUBLE_ARROW));
1201    #else
1202                    window->set_cursor(
1203    # if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 20)
1204                        Gdk::Cursor::create(Gdk::SB_H_DOUBLE_ARROW)
1205    # else
1206                        Gdk::Cursor::create(
1207                            Glib::wrap(event->device, true)->get_seat()->get_display(),
1208                            Gdk::SB_H_DOUBLE_ARROW
1209                        )
1210    # endif
1211                    );
1212    #endif
1213                  cursor_is_resize = true;                  cursor_is_resize = true;
1214              }              }
1215          } else if (cursor_is_resize) {          } else if (cursor_is_resize) {
# Line 532  bool DimRegionChooser::is_in_resize_zone Line 1236  bool DimRegionChooser::is_in_resize_zone
1236          int nbZones = region->pDimensionDefinitions[dim].zones;          int nbZones = region->pDimensionDefinitions[dim].zones;
1237    
1238          int c = 0;          int c = 0;
1239          if (dimregno >= 0) {          if (maindimregno >= 0) {
1240              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);              int mask = ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << bitpos);
1241              c = dimregno & mask; // mask away this dimension              c = maindimregno & mask; // mask away this dimension
1242          }          }
1243          const bool customsplits =          const bool customsplits =
1244              ((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 1250  bool DimRegionChooser::is_in_resize_zone
1250          if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {          if (region->pDimensionDefinitions[dim].split_type != gig::split_type_bit) {
1251              int prev_limit = 0;              int prev_limit = 0;
1252              for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {              for (int iZone = 0 ; iZone < nbZones - 1 ; iZone++) {
1253                  gig::DimensionRegion *d = region->pDimensionRegions[c + (iZone << bitpos)];                  gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
1254                  const int upperLimit =                  const int upperLimit =
1255                      (customsplits) ?                      (customsplits) ?
1256                          (d->DimensionUpperLimits[dim]) ?                          (d->DimensionUpperLimits[dim]) ?
# Line 557  bool DimRegionChooser::is_in_resize_zone Line 1261  bool DimRegionChooser::is_in_resize_zone
1261                  if (x <= limitx - 2) break;                  if (x <= limitx - 2) break;
1262                  if (x <= limitx + 2) {                  if (x <= limitx + 2) {
1263                      resize.dimension = dim;                      resize.dimension = dim;
1264                      resize.offset = iZone << bitpos;                      resize.dimensionDef = region->pDimensionDefinitions[dim];
1265                        resize.zone = iZone;
1266                      resize.pos = limit;                      resize.pos = limit;
1267                      resize.min = prev_limit;                      resize.min = prev_limit;
1268    
1269                      int dr = (dimregno >> bitpos) &                      int dr = (maindimregno >> bitpos) &
1270                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);                          ((1 << region->pDimensionDefinitions[dim].bits) - 1);
1271                      resize.selected = dr == iZone ? resize.left :                      resize.selected = dr == iZone ? resize.left :
1272                          dr == iZone + 1 ? resize.right : resize.none;                          dr == iZone + 1 ? resize.right : resize.none;
1273    
1274                      iZone++;                      iZone++;
1275                      gig::DimensionRegion *d = region->pDimensionRegions[c + (iZone << bitpos)];                      gig::DimensionRegion* d = region->pDimensionRegions[c + (iZone << bitpos)];
1276    
1277                      const int upperLimit =                      const int upperLimit =
1278                          (customsplits) ?                          (customsplits) ?
# Line 598  sigc::signal<void>& DimRegionChooser::si Line 1303  sigc::signal<void>& DimRegionChooser::si
1303    
1304  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)  bool DimRegionChooser::on_focus(Gtk::DirectionType direction)
1305  {  {
1306      // 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
1307      // fokus.      // to set focus
1308      if (direction == Gtk::DIR_TAB_FORWARD ||      if (direction == Gtk::DIR_TAB_FORWARD ||
1309          direction == Gtk::DIR_DOWN) {          direction == Gtk::DIR_DOWN) {
1310          if (!has_focus()) {          if (!has_focus()) {
# Line 631  bool DimRegionChooser::on_focus(Gtk::Dir Line 1336  bool DimRegionChooser::on_focus(Gtk::Dir
1336              }              }
1337          }          }
1338      } else if (!has_focus()) {      } else if (!has_focus()) {
1339          // TODO: kolla att focus_line finns!          // TODO: check that focus_line exists
1340          grab_focus();          grab_focus();
1341          return true;          return true;
1342      } else {      } else {
1343          // TODO: öka eller minska värde!          // TODO: increase or decrease value
1344        }
1345        return false;
1346    }
1347    
1348    void DimRegionChooser::split_dimension_zone() {    
1349        printf("split_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1350        try {
1351            if (!modifyallregions) {
1352                region->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1353            } else {
1354                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1355                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1356                assert(pMaindimdef != NULL);
1357                // retain structure by value since the original region will be
1358                // modified in the loop below as well
1359                gig::dimension_def_t maindimdef = *pMaindimdef;
1360                std::vector<gig::Region*> ignoredAll;
1361                std::vector<gig::Region*> ignoredMinor;
1362                std::vector<gig::Region*> ignoredCritical;
1363                gig::Region* rgn = NULL;
1364                for (int key = 0; key < 128; ++key) {
1365                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1366                    rgn = instr->GetRegion(key);
1367    
1368                    // ignore all regions which do not exactly match the dimension
1369                    // layout of the selected region where this operation was emitted
1370                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1371                    if (!dimdef) {
1372                        ignoredAll.push_back(rgn);
1373                        ignoredMinor.push_back(rgn);
1374                        continue;
1375                    }
1376                    if (dimdef->zones != maindimdef.zones) {
1377                        ignoredAll.push_back(rgn);
1378                        ignoredCritical.push_back(rgn);
1379                        continue;
1380                    }
1381    
1382                    rgn->SplitDimensionZone(maindimtype, maindimcase[maindimtype]);
1383                }
1384                if (!ignoredAll.empty()) {
1385                    Glib::ustring txt;
1386                    if (ignoredCritical.empty())
1387                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1388                    else if (ignoredMinor.empty())
1389                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1390                    else
1391                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1392                        ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1393                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1394                    Gtk::MessageDialog msg(txt, false, type);
1395                    msg.run();
1396                }
1397            }
1398        } catch (RIFF::Exception e) {
1399            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1400            msg.run();
1401        } catch (...) {
1402            Glib::ustring txt = _("An unknown exception occurred!");
1403            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1404            msg.run();
1405        }
1406        refresh_all();
1407    }
1408    
1409    void DimRegionChooser::delete_dimension_zone() {
1410        printf("delete_dimension_zone() type=%d, zone=%d\n", maindimtype, maindimcase[maindimtype]);
1411        try {
1412            if (!modifyallregions) {
1413                region->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1414            } else {
1415                gig::Instrument* instr = (gig::Instrument*)region->GetParent();
1416                gig::dimension_def_t* pMaindimdef = region->GetDimensionDefinition(maindimtype);
1417                assert(pMaindimdef != NULL);
1418                // retain structure by value since the original region will be
1419                // modified in the loop below as well
1420                gig::dimension_def_t maindimdef = *pMaindimdef;
1421                std::vector<gig::Region*> ignoredAll;
1422                std::vector<gig::Region*> ignoredMinor;
1423                std::vector<gig::Region*> ignoredCritical;
1424                gig::Region* rgn = NULL;
1425                for (int key = 0; key < 128; ++key) {
1426                    if (!instr->GetRegion(key) || instr->GetRegion(key) == rgn) continue;
1427                    rgn = instr->GetRegion(key);
1428    
1429                    // ignore all regions which do not exactly match the dimension
1430                    // layout of the selected region where this operation was emitted
1431                    gig::dimension_def_t* dimdef = rgn->GetDimensionDefinition(maindimtype);
1432                    if (!dimdef) {
1433                        ignoredAll.push_back(rgn);
1434                        ignoredMinor.push_back(rgn);
1435                        continue;
1436                    }
1437                    if (dimdef->zones != maindimdef.zones) {
1438                        ignoredAll.push_back(rgn);
1439                        ignoredCritical.push_back(rgn);
1440                        continue;
1441                    }
1442    
1443                    rgn->DeleteDimensionZone(maindimtype, maindimcase[maindimtype]);
1444                }
1445                if (!ignoredAll.empty()) {
1446                    Glib::ustring txt;
1447                    if (ignoredCritical.empty())
1448                        txt = ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type.");
1449                    else if (ignoredMinor.empty())
1450                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones!");
1451                    else
1452                        txt = ToString(ignoredCritical.size()) + _(" regions have been ignored due to different amount of dimension zones (and ") +
1453                              ToString(ignoredMinor.size()) + _(" regions have been ignored since they don't have that dimension type)!");
1454                    Gtk::MessageType type = (ignoredCritical.empty()) ? Gtk::MESSAGE_INFO : Gtk::MESSAGE_WARNING;
1455                    Gtk::MessageDialog msg(txt, false, type);
1456                    msg.run();
1457                }
1458            }
1459        } catch (RIFF::Exception e) {
1460            Gtk::MessageDialog msg(e.Message, false, Gtk::MESSAGE_ERROR);
1461            msg.run();
1462        } catch (...) {
1463            Glib::ustring txt = _("An unknown exception occurred!");
1464            Gtk::MessageDialog msg(txt, false, Gtk::MESSAGE_ERROR);
1465            msg.run();
1466        }
1467        refresh_all();
1468    }
1469    
1470    // Cmd key on Mac, Ctrl key on all other OSs
1471    static const guint primaryKeyL =
1472        #if defined(__APPLE__)
1473        GDK_KEY_Meta_L;
1474        #else
1475        GDK_KEY_Control_L;
1476        #endif
1477    
1478    static const guint primaryKeyR =
1479        #if defined(__APPLE__)
1480        GDK_KEY_Meta_R;
1481        #else
1482        GDK_KEY_Control_R;
1483        #endif
1484    
1485    #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION > 91 || (GTKMM_MINOR_VERSION == 91 && GTKMM_MICRO_VERSION >= 2))) // GTKMM >= 3.91.2
1486    bool DimRegionChooser::onKeyPressed(Gdk::EventKey& _key) {
1487        GdkEventKey* key = _key.gobj();
1488    #else
1489    bool DimRegionChooser::onKeyPressed(GdkEventKey* key) {
1490    #endif
1491        //printf("key down 0x%x\n", key->keyval);
1492        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1493            multiSelectKeyDown = true;
1494        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1495            primaryKeyDown = true;
1496        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1497            shiftKeyDown = true;
1498    
1499        //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
1500        /*if (key->keyval == GDK_KEY_Left)
1501            select_prev_dimzone();
1502        if (key->keyval == GDK_KEY_Right)
1503            select_next_dimzone();
1504        if (key->keyval == GDK_KEY_Up)
1505            select_prev_dimension();
1506        if (key->keyval == GDK_KEY_Down)
1507            select_next_dimension();*/
1508        return false;
1509    }
1510    
1511    #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION > 91 || (GTKMM_MINOR_VERSION == 91 && GTKMM_MICRO_VERSION >= 2))) // GTKMM >= 3.91.2
1512    bool DimRegionChooser::onKeyReleased(Gdk::EventKey& _key) {
1513        GdkEventKey* key = _key.gobj();
1514    #else
1515    bool DimRegionChooser::onKeyReleased(GdkEventKey* key) {
1516    #endif
1517        //printf("key up 0x%x\n", key->keyval);
1518        if (key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
1519            multiSelectKeyDown = false;
1520        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
1521            primaryKeyDown = false;
1522        if (key->keyval == GDK_KEY_Shift_L || key->keyval == GDK_KEY_Shift_R)
1523            shiftKeyDown = false;
1524    
1525        if (!has_focus()) return false;
1526    
1527        // avoid conflict with Ctrl+Left and Ctrl+Right accelerators on mainwindow
1528        // (which is supposed to switch between regions)
1529        if (primaryKeyDown) return false;
1530    
1531        // avoid conflict with Alt+Shift+Left and Alt+Shift+Right accelerators on
1532        // mainwindow
1533        if (shiftKeyDown) return false;
1534    
1535        if (key->keyval == GDK_KEY_Left)
1536            select_prev_dimzone();
1537        if (key->keyval == GDK_KEY_Right)
1538            select_next_dimzone();
1539        if (key->keyval == GDK_KEY_Up)
1540            select_prev_dimension();
1541        if (key->keyval == GDK_KEY_Down)
1542            select_next_dimension();
1543    
1544        return false;
1545    }
1546    
1547    void DimRegionChooser::resetSelectedZones() {
1548        this->dimzones.clear();
1549        if (!region) {
1550            queue_draw(); // redraw required parts
1551            return;
1552        }
1553        if (maindimregno < 0 || maindimregno >= region->DimensionRegions) {
1554            queue_draw(); // redraw required parts
1555            return;
1556        }
1557        if (!region->pDimensionRegions[maindimregno]) {
1558            queue_draw(); // redraw required parts
1559            return;
1560        }
1561        gig::DimensionRegion* dimrgn = region->pDimensionRegions[maindimregno];
1562    
1563        bool isValidZone;
1564        this->maindimcase = dimensionCaseOf(dimrgn);
1565    
1566        for (std::map<gig::dimension_t,int>::const_iterator it = this->maindimcase.begin();
1567             it != this->maindimcase.end(); ++it)
1568        {
1569            this->dimzones[it->first].insert(it->second);
1570        }
1571    
1572        // redraw required parts
1573        queue_draw();
1574    }
1575    
1576    bool DimRegionChooser::select_dimregion(gig::DimensionRegion* dimrgn) {
1577        if (!region) return false; //.selection failed
1578    
1579        for (int dr = 0; dr < region->DimensionRegions && region->pDimensionRegions[dr]; ++dr) {
1580            if (region->pDimensionRegions[dr] == dimrgn) {
1581                // reset dim region zone selection to the requested specific dim region case
1582                maindimregno = dr;
1583                resetSelectedZones();
1584    
1585                // emit signal that dimregion selection has changed, for external entities
1586                dimregion_selected();
1587    
1588                return true; // selection success
1589            }
1590        }
1591    
1592        return false; //.selection failed
1593    }
1594    
1595    void DimRegionChooser::select_next_dimzone(bool add) {
1596        select_dimzone_by_dir(+1, add);
1597    }
1598    
1599    void DimRegionChooser::select_prev_dimzone(bool add) {
1600        select_dimzone_by_dir(-1, add);
1601    }
1602    
1603    void DimRegionChooser::select_dimzone_by_dir(int dir, bool add) {
1604        if (!region) return;
1605        if (!region->Dimensions) return;
1606        if (focus_line < 0) focus_line = 0;
1607        if (focus_line >= region->Dimensions) focus_line = region->Dimensions - 1;
1608    
1609        maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1610        if (maindimtype == gig::dimension_none) {
1611            printf("maindimtype -> none\n");
1612            return;
1613        }
1614    
1615        // commented out: re-evaluate maindimcase, since it might not been reset from a previous instrument which causes errors if it got different dimension types
1616        //if (maindimcase.empty()) {
1617            maindimcase = dimensionCaseOf(region->pDimensionRegions[maindimregno]);
1618            if (maindimcase.empty()) {
1619                printf("caseOfDimregion(%d) -> empty\n", maindimregno);
1620                return;
1621            }
1622        //}
1623    
1624        int z = (dir > 0) ? maindimcase[maindimtype] + 1 : maindimcase[maindimtype] - 1;
1625        if (z < 0) z = 0;
1626        if (z >= region->pDimensionDefinitions[focus_line].zones)
1627            z = region->pDimensionDefinitions[focus_line].zones - 1;
1628    
1629        maindimcase[maindimtype] = z;
1630    
1631        ::gig::DimensionRegion* dr = dimensionRegionMatching(maindimcase, region);
1632        if (!dr) {
1633            printf("select_dimzone_by_dir(%d) -> !dr\n", dir);
1634            return;
1635      }      }
1636    
1637        maindimregno = getDimensionRegionIndex(dr);
1638    
1639        if (!add) {
1640            // reset selected dimregion zones
1641            dimzones.clear();
1642        }
1643        for (DimensionCase::const_iterator it = maindimcase.begin();
1644             it != maindimcase.end(); ++it)
1645        {
1646            dimzones[it->first].insert(it->second);
1647        }
1648    
1649        dimregion_selected();
1650    
1651        // disabled: would overwrite dimregno with wrong value
1652        //refresh_all();
1653        // so requesting just a raw repaint instead:
1654        queue_draw();
1655    }
1656    
1657    void DimRegionChooser::select_next_dimension() {
1658        if (!region) return;
1659        focus_line++;
1660        if (focus_line >= region->Dimensions)
1661            focus_line = region->Dimensions - 1;
1662        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1663        queue_draw();
1664    }
1665    
1666    void DimRegionChooser::select_prev_dimension() {
1667        if (!region) return;
1668        focus_line--;
1669        if (focus_line < 0)
1670            focus_line = 0;
1671        this->maindimtype = region->pDimensionDefinitions[focus_line].dimension;
1672        queue_draw();
1673    }
1674    
1675    gig::DimensionRegion* DimRegionChooser::get_main_dimregion() const {
1676        if (!region) return NULL;
1677        return region->pDimensionRegions[maindimregno];
1678  }  }

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

  ViewVC Help
Powered by ViewVC