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

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

  ViewVC Help
Powered by ViewVC